Skip to content

Commit bea77b8

Browse files
fmauchmergify[bot]
authored andcommitted
Urscript interface (#721)
* Add a urscript interface node * Add urscript_interface to standard launchfile * Added documentation for urscript_interface * Add a notice about incorrect script code * Add test for urscript interface * Move tests to one single tests This should avoid that different tests run in parallel * Wait for IO controller before checking IOs * Write an initial textmessage when connecting the urscript_interface * Wait for controller_manager services longer * Make sure we have a clean robot state without any program running once we enter our test similar to how we did it on the robot_driver test * Remove unneeded Destructor definition (cherry picked from commit 7ee47bd) # Conflicts: # ur_robot_driver/doc/usage.rst
1 parent f7b8802 commit bea77b8

File tree

5 files changed

+477
-1
lines changed

5 files changed

+477
-1
lines changed

ur_robot_driver/CMakeLists.txt

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,8 +103,13 @@ add_executable(controller_stopper_node
103103
)
104104
ament_target_dependencies(controller_stopper_node ${${PROJECT_NAME}_EXPORTED_TARGETS} ${THIS_PACKAGE_INCLUDE_DEPENDS})
105105

106+
add_executable(urscript_interface
107+
src/urscript_interface.cpp
108+
)
109+
ament_target_dependencies(urscript_interface ${${PROJECT_NAME}_EXPORTED_TARGETS} ${THIS_PACKAGE_INCLUDE_DEPENDS})
110+
106111
install(
107-
TARGETS dashboard_client ur_ros2_control_node controller_stopper_node
112+
TARGETS dashboard_client ur_ros2_control_node controller_stopper_node urscript_interface
108113
DESTINATION lib/${PROJECT_NAME}
109114
)
110115

@@ -182,5 +187,9 @@ if(BUILD_TESTING)
182187
TIMEOUT
183188
500
184189
)
190+
add_launch_test(test/urscript_interface.py
191+
TIMEOUT
192+
500
193+
)
185194
endif()
186195
endif()

ur_robot_driver/doc/usage.rst

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -239,4 +239,78 @@ Then start
239239
240240
ros2 launch ur_robot_driver ur_control.launch.py ur_type:=ur5e robot_ip:=yyy.yyy.yyy.yyy use_fake_hardware:=true launch_rviz:=false initial_joint_controller:=joint_trajectory_controller
241241
# and in another shell
242+
<<<<<<< HEAD
242243
ros2 launch ur_moveit_config ur_moveit.launch.py ur_type:=ur5e launch_rviz:=true
244+
=======
245+
ros2 launch ur_moveit_config ur_moveit.launch.py ur_type:=ur5e launch_rviz:=true use_fake_hardware:=true
246+
247+
Robot frames
248+
------------
249+
250+
While most tf frames come from the URDF and are published from the ``robot_state_publisher``, there
251+
are a couple of things to know:
252+
253+
- The ``base`` frame is the robot's base as the robot controller sees it.
254+
- The ``tool0_controller`` is the tool frame as published from the robot controller. If there is no
255+
additional tool configured on the Teach pendant (TP), this should be equivalent to ``tool0`` given that
256+
the URDF uses the specific robot's :ref:`calibration <calibration_extraction>`. If a tool is
257+
configured on the TP, then the additional transformation will show in ``base`` -> ``tool0``.
258+
259+
Custom URScript commands
260+
------------------------
261+
262+
The driver's package contains a ``urscript_interface`` node that allows sending URScript snippets
263+
directly to the robot. It gets started in the driver's launchfiles by default. To use it, simply
264+
publish a message to its interface:
265+
266+
.. code-block:: bash
267+
268+
# simple popup
269+
ros2 topic pub /urscript_interface/script_command std_msgs/msg/String '{data: popup("hello")}' --once
270+
271+
Be aware, that running a program on this interface (meaning publishing script code to that interface) stops any running program on the robot.
272+
Thus, the motion-interpreting program that is started by the driver gets stopped and has to be
273+
restarted again. Depending whether you use headless mode or not, you'll have to call the
274+
``resend_program`` service or press the ``play`` button on the teach panel to start the
275+
external_control program again.
276+
277+
.. note::
278+
Currently, there is no feedback on the code's correctness. If the code sent to the
279+
robot is incorrect, it will silently not get executed. Make sure that you send valid URScript code!
280+
281+
Multi-line programs
282+
^^^^^^^^^^^^^^^^^^^
283+
284+
When you want to define multi-line programs, make sure to check that newlines are correctly
285+
interpreted from your message. For this purpose the driver prints the program as it is being sent to
286+
the robot. When sending a multi-line program from the command line, you can use an empty line
287+
between each statement:
288+
289+
.. code-block:: bash
290+
291+
ros2 topic pub --once /urscript_interface/script_command std_msgs/msg/String '{data:
292+
"def my_prog():
293+
294+
set_digital_out(1, True)
295+
296+
movej(p[0.2, 0.3, 0.8, 0, 0, 3.14], a=1.2, v=0.25, r=0)
297+
298+
textmsg(\"motion finished\")
299+
300+
end"}'
301+
302+
Non-interrupting programs
303+
^^^^^^^^^^^^^^^^^^^^^^^^^
304+
305+
To prevent interrupting the main program, you can send certain commands as `secondary programs
306+
<https://www.universal-robots.com/articles/ur/programming/secondary-program/>`_.
307+
308+
.. code-block:: bash
309+
310+
ros2 topic pub --once /urscript_interface/script_command std_msgs/msg/String '{data:
311+
"sec my_prog():
312+
313+
textmsg(\"This is a log message\")
314+
315+
end"}'
316+
>>>>>>> 7ee47bd (Urscript interface (#721))

ur_robot_driver/launch/ur_control.launch.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -243,6 +243,13 @@ def launch_setup(context, *args, **kwargs):
243243
],
244244
)
245245

246+
urscript_interface = Node(
247+
package="ur_robot_driver",
248+
executable="urscript_interface",
249+
parameters=[{"robot_ip": robot_ip}],
250+
output="screen",
251+
)
252+
246253
controller_stopper_node = Node(
247254
package="ur_robot_driver",
248255
executable="controller_stopper_node",
@@ -341,6 +348,7 @@ def controller_spawner(name, active=True):
341348
dashboard_client_node,
342349
tool_communication_node,
343350
controller_stopper_node,
351+
urscript_interface,
344352
robot_state_publisher_node,
345353
rviz_node,
346354
initial_joint_controller_spawner_stopped,
Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
// Copyright 2023, FZI Forschungszentrum Informatik, Created on behalf of Universal Robots A/S
2+
//
3+
// Redistribution and use in source and binary forms, with or without
4+
// modification, are permitted provided that the following conditions are met:
5+
//
6+
// * Redistributions of source code must retain the above copyright
7+
// notice, this list of conditions and the following disclaimer.
8+
//
9+
// * Redistributions in binary form must reproduce the above copyright
10+
// notice, this list of conditions and the following disclaimer in the
11+
// documentation and/or other materials provided with the distribution.
12+
//
13+
// * Neither the name of the {copyright_holder} nor the names of its
14+
// contributors may be used to endorse or promote products derived from
15+
// this software without specific prior written permission.
16+
//
17+
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18+
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19+
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20+
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
21+
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22+
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23+
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24+
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25+
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26+
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27+
// POSSIBILITY OF SUCH DAMAGE.
28+
29+
//----------------------------------------------------------------------
30+
/*!\file
31+
*
32+
* \author Felix Exner [email protected]
33+
* \date 2023-06-20
34+
*
35+
*/
36+
//----------------------------------------------------------------------
37+
38+
#include <ur_client_library/comm/stream.h>
39+
#include <ur_client_library/primary/primary_package.h>
40+
41+
#include <memory>
42+
43+
#include <rclcpp/rclcpp.hpp>
44+
#include <std_msgs/msg/string.hpp>
45+
46+
class URScriptInterface : public rclcpp::Node
47+
{
48+
public:
49+
URScriptInterface()
50+
: Node("urscript_interface")
51+
, m_script_sub(this->create_subscription<std_msgs::msg::String>(
52+
"~/script_command", 1, [this](const std_msgs::msg::String::SharedPtr msg) {
53+
auto program_with_newline = msg->data + '\n';
54+
55+
RCLCPP_INFO_STREAM(this->get_logger(), program_with_newline);
56+
57+
size_t len = program_with_newline.size();
58+
const auto* data = reinterpret_cast<const uint8_t*>(program_with_newline.c_str());
59+
size_t written;
60+
61+
if (m_secondary_stream->write(data, len, written)) {
62+
URCL_LOG_INFO("Sent program to robot:\n%s", program_with_newline.c_str());
63+
return true;
64+
}
65+
URCL_LOG_ERROR("Could not send program to robot");
66+
return false;
67+
}))
68+
{
69+
this->declare_parameter("robot_ip", rclcpp::PARAMETER_STRING);
70+
m_secondary_stream = std::make_unique<urcl::comm::URStream<urcl::primary_interface::PrimaryPackage>>(
71+
this->get_parameter("robot_ip").as_string(), urcl::primary_interface::UR_SECONDARY_PORT);
72+
m_secondary_stream->connect();
73+
74+
auto program_with_newline = std::string("textmsg(\"urscript_interface connected\")\n");
75+
size_t len = program_with_newline.size();
76+
const auto* data = reinterpret_cast<const uint8_t*>(program_with_newline.c_str());
77+
size_t written;
78+
m_secondary_stream->write(data, len, written);
79+
}
80+
81+
private:
82+
rclcpp::Subscription<std_msgs::msg::String>::SharedPtr m_script_sub;
83+
std::unique_ptr<urcl::comm::URStream<urcl::primary_interface::PrimaryPackage>> m_secondary_stream;
84+
};
85+
86+
int main(int argc, char** argv)
87+
{
88+
rclcpp::init(argc, argv);
89+
rclcpp::spin(std::make_unique<URScriptInterface>());
90+
rclcpp::shutdown();
91+
return 0;
92+
}

0 commit comments

Comments
 (0)