Skip to content

Commit 114f68f

Browse files
committed
Add torque control example
1 parent 46c1dd6 commit 114f68f

File tree

2 files changed

+131
-0
lines changed

2 files changed

+131
-0
lines changed

examples/CMakeLists.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,10 @@ add_executable(script_command_interface_example
4848
script_command_interface.cpp)
4949
target_link_libraries(script_command_interface_example ur_client_library::urcl)
5050

51+
add_executable(torque_control_example
52+
torque_control.cpp)
53+
target_link_libraries(torque_control_example ur_client_library::urcl)
54+
5155
add_executable(trajectory_point_interface_example
5256
trajectory_point_interface.cpp)
5357
target_link_libraries(trajectory_point_interface_example ur_client_library::urcl)

examples/torque_control.cpp

Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
// -- BEGIN LICENSE BLOCK ----------------------------------------------
2+
// Copyright 2025 Universal Robots A/S
3+
//
4+
// Redistribution and use in source and binary forms, with or without
5+
// modification, are permitted provided that the following conditions are met:
6+
//
7+
// * Redistributions of source code must retain the above copyright
8+
// notice, this list of conditions and the following disclaimer.
9+
//
10+
// * Redistributions in binary form must reproduce the above copyright
11+
// notice, this list of conditions and the following disclaimer in the
12+
// documentation and/or other materials provided with the distribution.
13+
//
14+
// * Neither the name of the {copyright_holder} nor the names of its
15+
// contributors may be used to endorse or promote products derived from
16+
// this software without specific prior written permission.
17+
//
18+
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19+
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20+
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21+
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
22+
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23+
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24+
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25+
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26+
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27+
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28+
// POSSIBILITY OF SUCH DAMAGE.
29+
// -- END LICENSE BLOCK ------------------------------------------------
30+
31+
#include <ur_client_library/example_robot_wrapper.h>
32+
33+
// In a real-world example it would be better to get those values from command line parameters / a
34+
// better configuration system such as Boost.Program_options
35+
const std::string DEFAULT_ROBOT_IP = "192.168.56.101";
36+
const std::string SCRIPT_FILE = "resources/external_control.urscript";
37+
const std::string OUTPUT_RECIPE = "examples/resources/rtde_output_recipe.txt";
38+
const std::string INPUT_RECIPE = "examples/resources/rtde_input_recipe.txt";
39+
40+
std::unique_ptr<urcl::ExampleRobotWrapper> g_my_robot;
41+
urcl::vector6d_t g_joint_positions;
42+
43+
int main(int argc, char* argv[])
44+
{
45+
urcl::setLogLevel(urcl::LogLevel::INFO);
46+
47+
// Parse the ip arguments if given
48+
std::string robot_ip = DEFAULT_ROBOT_IP;
49+
if (argc > 1)
50+
{
51+
robot_ip = std::string(argv[1]);
52+
}
53+
54+
bool headless_mode = true;
55+
g_my_robot = std::make_unique<urcl::ExampleRobotWrapper>(robot_ip, OUTPUT_RECIPE, INPUT_RECIPE, headless_mode,
56+
"external_control.urp");
57+
if (!g_my_robot->isHealthy())
58+
{
59+
URCL_LOG_ERROR("Something in the robot initialization went wrong. Exiting. Please check the output above.");
60+
return 1;
61+
}
62+
// --------------- INITIALIZATION END -------------------
63+
64+
bool passed_negative_part = false;
65+
bool passed_positive_part = false;
66+
URCL_LOG_INFO("Start moving the robot");
67+
urcl::vector6d_t target_torques = { 2.0, 0, 0, 0, 0, 0 };
68+
69+
// Once RTDE communication is started, we have to make sure to read from the interface buffer, as
70+
// otherwise we will get pipeline overflows. Therefor, do this directly before starting your main
71+
// loop.
72+
g_my_robot->getUrDriver()->startRTDECommunication();
73+
while (!(passed_positive_part && passed_negative_part))
74+
{
75+
// Read latest RTDE package. This will block for a hard-coded timeout (see UrDriver), so the
76+
// robot will effectively be in charge of setting the frequency of this loop.
77+
// In a real-world application this thread should be scheduled with real-time priority in order
78+
// to ensure that this is called in time.
79+
std::unique_ptr<urcl::rtde_interface::DataPackage> data_pkg = g_my_robot->getUrDriver()->getDataPackage();
80+
if (!data_pkg)
81+
{
82+
URCL_LOG_WARN("Could not get fresh data package from robot");
83+
return 1;
84+
}
85+
// Read current joint positions from robot data
86+
if (!data_pkg->getData("actual_q", g_joint_positions))
87+
{
88+
// This throwing should never happen unless misconfigured
89+
std::string error_msg = "Did not find 'actual_q' in data sent from robot. This should not happen!";
90+
throw std::runtime_error(error_msg);
91+
}
92+
93+
// Open loop control. The target is incremented with a constant each control loop
94+
if (passed_positive_part == false)
95+
{
96+
if (g_joint_positions[0] >= 2)
97+
{
98+
target_torques[0] = -2.0;
99+
passed_positive_part = true;
100+
}
101+
}
102+
else if (passed_negative_part == false)
103+
{
104+
if (g_joint_positions[0] <= 0)
105+
{
106+
target_torques[0] = 2.0;
107+
passed_negative_part = true;
108+
}
109+
}
110+
111+
// Setting the RobotReceiveTimeout time is for example purposes only. This will make the example running more
112+
// reliable on non-realtime systems. Use with caution in productive applications. Having it
113+
// this high means that the robot will continue a motion for this given time if no new command
114+
// is sent / the connection is interrupted.
115+
bool ret = g_my_robot->getUrDriver()->writeJointCommand(target_torques, urcl::comm::ControlMode::MODE_TORQUE,
116+
urcl::RobotReceiveTimeout::millisec(100));
117+
if (!ret)
118+
{
119+
URCL_LOG_ERROR("Could not send joint command. Is the robot in remote control?");
120+
return 1;
121+
}
122+
URCL_LOG_DEBUG("data_pkg:\n%s", data_pkg->toString().c_str());
123+
}
124+
g_my_robot->getUrDriver()->stopControl();
125+
URCL_LOG_INFO("Movement done");
126+
return 0;
127+
}

0 commit comments

Comments
 (0)