Skip to content

Commit 5edaef4

Browse files
committed
Update example documentation for ur_driver example
1 parent 07a2147 commit 5edaef4

File tree

2 files changed

+131
-49
lines changed

2 files changed

+131
-49
lines changed

doc/examples/ur_driver.rst

Lines changed: 61 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,72 @@
22

33
.. _example-driver:
44

5-
Example driver TODO
5+
Example driver
66
==============
77
In the ``examples`` subfolder you will find a minimal example of a running driver. It starts an
88
instance of the ``UrDriver`` class and prints the RTDE values read from the controller. To run it make
99
sure to
1010

1111
* have an instance of a robot controller / URSim running at the configured IP address (or adapt the
1212
address to your needs)
13-
* run it from the package's main folder (the one where this README.md file is stored), as for
13+
* run it from the package's main folder (the one where the README.md file is stored), as for
1414
simplicity reasons it doesn't use any sophisticated method to locate the required files.
15+
16+
This page will walk you through the `full_driver.cpp
17+
<https://github.com/UniversalRobots/Universal_Robots_Client_Library/blob/master/examples/full_driver.cpp>`_
18+
example.
19+
20+
Initialization
21+
--------------
22+
23+
At first, we create a ``UrDriver`` object giving it the robot's IP address, script file and RTDE
24+
recipes.
25+
26+
.. literalinclude:: ../../examples/full_driver.cpp
27+
:language: c++
28+
:caption: examples/full_driver.cpp
29+
:linenos:
30+
:lineno-match:
31+
:start-at: std::unique_ptr<ToolCommSetup> tool_comm_setup;
32+
:end-at: std::move(tool_comm_setup)
33+
34+
Robot control loop
35+
------------------
36+
37+
This example reads the robot's joint positions, increments / decrements the 5th axis and sends that
38+
back as a joint command for the next cycle. This way, the robot will move its wrist first until a
39+
positive limit and then back to 0.
40+
41+
To read the joint data, the driver's RTDE client is used:
42+
43+
44+
.. literalinclude:: ../../examples/full_driver.cpp
45+
:language: c++
46+
:caption: examples/full_driver.cpp
47+
:linenos:
48+
:lineno-match:
49+
:start-at: // Once RTDE communication is started
50+
:end-before: // Open loop control
51+
52+
The first read operation will initialize the target buffer with the current robot position. Next,
53+
the target joint configuration is calculated:
54+
55+
56+
.. literalinclude:: ../../examples/full_driver.cpp
57+
:language: c++
58+
:caption: examples/full_driver.cpp
59+
:linenos:
60+
:lineno-match:
61+
:start-at: // Open loop control
62+
:end-at: joint_target[5] += increment
63+
64+
To send the control command, the robot's :ref:`reverse_interface` is used via the
65+
``writeJointCommand()`` function:
66+
67+
.. literalinclude:: ../../examples/full_driver.cpp
68+
:language: c++
69+
:caption: examples/full_driver.cpp
70+
:linenos:
71+
:lineno-match:
72+
:start-at: // Setting the RobotReceiveTimeout
73+
:end-before: URCL_LOG_DEBUG("data_pkg:\n%s", data_pkg->toString().c_str());

examples/full_driver.cpp

Lines changed: 70 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -43,17 +43,37 @@ const std::string DEFAULT_ROBOT_IP = "192.168.56.101";
4343
const std::string SCRIPT_FILE = "resources/external_control.urscript";
4444
const std::string OUTPUT_RECIPE = "examples/resources/rtde_output_recipe.txt";
4545
const std::string INPUT_RECIPE = "examples/resources/rtde_input_recipe.txt";
46-
const std::string CALIBRATION_CHECKSUM = "calib_12788084448423163542";
4746

4847
std::unique_ptr<UrDriver> g_my_driver;
4948
std::unique_ptr<DashboardClient> g_my_dashboard;
5049
vector6d_t g_joint_positions;
5150

51+
std::condition_variable g_program_running_cv;
52+
std::mutex g_program_running_mutex;
53+
bool g_program_running;
54+
5255
// We need a callback function to register. See UrDriver's parameters for details.
5356
void handleRobotProgramState(bool program_running)
5457
{
5558
// Print the text in green so we see it better
5659
std::cout << "\033[1;32mProgram running: " << std::boolalpha << program_running << "\033[0m\n" << std::endl;
60+
if (program_running)
61+
{
62+
std::lock_guard<std::mutex> lk(g_program_running_mutex);
63+
g_program_running = program_running;
64+
g_program_running_cv.notify_one();
65+
}
66+
}
67+
68+
bool waitForProgramRunning(int milliseconds = 100)
69+
{
70+
std::unique_lock<std::mutex> lk(g_program_running_mutex);
71+
if (g_program_running_cv.wait_for(lk, std::chrono::milliseconds(milliseconds)) == std::cv_status::no_timeout ||
72+
g_program_running == true)
73+
{
74+
return true;
75+
}
76+
return false;
5777
}
5878

5979
int main(int argc, char* argv[])
@@ -109,13 +129,13 @@ int main(int argc, char* argv[])
109129
std::unique_ptr<ToolCommSetup> tool_comm_setup;
110130
const bool headless = true;
111131
g_my_driver.reset(new UrDriver(robot_ip, SCRIPT_FILE, OUTPUT_RECIPE, INPUT_RECIPE, &handleRobotProgramState, headless,
112-
std::move(tool_comm_setup), CALIBRATION_CHECKSUM));
113-
114-
// Once RTDE communication is started, we have to make sure to read from the interface buffer, as
115-
// otherwise we will get pipeline overflows. Therefor, do this directly before starting your main
116-
// loop.
117-
118-
g_my_driver->startRTDECommunication();
132+
std::move(tool_comm_setup)));
133+
// Make sure that external control script is running
134+
if (!waitForProgramRunning())
135+
{
136+
URCL_LOG_ERROR("External Control script not running.");
137+
return 1;
138+
}
119139

120140
// Increment depends on robot version
121141
double increment_constant = 0.0005;
@@ -130,62 +150,65 @@ int main(int argc, char* argv[])
130150
bool passed_positive_part = false;
131151
URCL_LOG_INFO("Start moving the robot");
132152
urcl::vector6d_t joint_target = { 0, 0, 0, 0, 0, 0 };
153+
154+
// Once RTDE communication is started, we have to make sure to read from the interface buffer, as
155+
// otherwise we will get pipeline overflows. Therefor, do this directly before starting your main
156+
// loop.
157+
g_my_driver->startRTDECommunication();
133158
while (!(passed_positive_part && passed_negative_part))
134159
{
135160
// Read latest RTDE package. This will block for a hard-coded timeout (see UrDriver), so the
136161
// robot will effectively be in charge of setting the frequency of this loop.
137162
// In a real-world application this thread should be scheduled with real-time priority in order
138163
// to ensure that this is called in time.
139164
std::unique_ptr<rtde_interface::DataPackage> data_pkg = g_my_driver->getDataPackage();
140-
if (data_pkg)
165+
if (!data_pkg)
141166
{
142-
// Read current joint positions from robot data
143-
if (!data_pkg->getData("actual_q", g_joint_positions))
144-
{
145-
// This throwing should never happen unless misconfigured
146-
std::string error_msg = "Did not find 'actual_q' in data sent from robot. This should not happen!";
147-
throw std::runtime_error(error_msg);
148-
}
167+
URCL_LOG_WARN("Could not get fresh data package from robot");
168+
return 1;
169+
}
170+
// Read current joint positions from robot data
171+
if (!data_pkg->getData("actual_q", g_joint_positions))
172+
{
173+
// This throwing should never happen unless misconfigured
174+
std::string error_msg = "Did not find 'actual_q' in data sent from robot. This should not happen!";
175+
throw std::runtime_error(error_msg);
176+
}
149177

150-
if (first_pass)
151-
{
152-
joint_target = g_joint_positions;
153-
first_pass = false;
154-
}
178+
if (first_pass)
179+
{
180+
joint_target = g_joint_positions;
181+
first_pass = false;
182+
}
155183

156-
// Open loop control. The target is incremented with a constant each control loop
157-
if (passed_positive_part == false)
158-
{
159-
increment = increment_constant;
160-
if (g_joint_positions[5] >= 2)
161-
{
162-
passed_positive_part = true;
163-
}
164-
}
165-
else if (passed_negative_part == false)
184+
// Open loop control. The target is incremented with a constant each control loop
185+
if (passed_positive_part == false)
186+
{
187+
increment = increment_constant;
188+
if (g_joint_positions[5] >= 2)
166189
{
167-
increment = -increment_constant;
168-
if (g_joint_positions[5] <= 0)
169-
{
170-
passed_negative_part = true;
171-
}
190+
passed_positive_part = true;
172191
}
173-
joint_target[5] += increment;
174-
// Setting the RobotReceiveTimeout time is for example purposes only. This will make the example running more
175-
// reliable on non-realtime systems. Use with caution in productive applications.
176-
bool ret = g_my_driver->writeJointCommand(joint_target, comm::ControlMode::MODE_SERVOJ,
177-
RobotReceiveTimeout::millisec(100));
178-
if (!ret)
192+
}
193+
else if (passed_negative_part == false)
194+
{
195+
increment = -increment_constant;
196+
if (g_joint_positions[5] <= 0)
179197
{
180-
URCL_LOG_ERROR("Could not send joint command. Is the robot in remote control?");
181-
return 1;
198+
passed_negative_part = true;
182199
}
183-
URCL_LOG_DEBUG("data_pkg:\n%s", data_pkg->toString().c_str());
184200
}
185-
else
201+
joint_target[5] += increment;
202+
// Setting the RobotReceiveTimeout time is for example purposes only. This will make the example running more
203+
// reliable on non-realtime systems. Use with caution in productive applications.
204+
bool ret = g_my_driver->writeJointCommand(joint_target, comm::ControlMode::MODE_SERVOJ,
205+
RobotReceiveTimeout::millisec(100));
206+
if (!ret)
186207
{
187-
URCL_LOG_WARN("Could not get fresh data package from robot");
208+
URCL_LOG_ERROR("Could not send joint command. Is the robot in remote control?");
209+
return 1;
188210
}
211+
URCL_LOG_DEBUG("data_pkg:\n%s", data_pkg->toString().c_str());
189212
}
190213
g_my_driver->stopControl();
191214
URCL_LOG_INFO("Movement done");

0 commit comments

Comments
 (0)