Skip to content

Commit 8e2ee63

Browse files
authored
Retry reading RTDE interface when unexpected messages appear during s… (#186)
* Retry reading RTDE interface when unexpected messages appear during startup At startup we make a couple of requests to the RTDE interface. If the interface publishes messages by itself, a simple read() from the interface might grab another message than the answer. This change checks whether an answer to our requests was received and reports a warning otherwise while retrying.
1 parent 8d8e909 commit 8e2ee63

File tree

2 files changed

+172
-70
lines changed

2 files changed

+172
-70
lines changed

ur_robot_driver/include/ur_robot_driver/rtde/rtde_client.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,9 @@ namespace ur_driver
4848
{
4949
namespace rtde_interface
5050
{
51+
static const uint16_t MAX_RTDE_PROTOCOL_VERSION = 2;
52+
static const unsigned MAX_REQUEST_RETRIES = 5;
53+
5154
enum class UrRtdeRobotStatusBits
5255
{
5356
IS_POWER_ON = 0,
@@ -166,7 +169,7 @@ class RTDEClient
166169

167170
std::vector<std::string> readRecipe(const std::string& recipe_file);
168171

169-
uint16_t negotiateProtocolVersion();
172+
bool negotiateProtocolVersion(const uint16_t protocol_version);
170173
void queryURControlVersion();
171174
void setupOutputs(const uint16_t protocol_version);
172175
void setupInputs();

ur_robot_driver/src/rtde/rtde_client.cpp

Lines changed: 168 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,18 @@ bool RTDEClient::init()
5151
pipeline_.init();
5252
pipeline_.run();
5353

54-
uint16_t protocol_version = negotiateProtocolVersion();
54+
uint16_t protocol_version = MAX_RTDE_PROTOCOL_VERSION;
55+
while (!negotiateProtocolVersion(protocol_version))
56+
{
57+
LOG_INFO("Robot did not accept RTDE protocol version '%hu'. Trying lower protocol version", protocol_version);
58+
protocol_version--;
59+
if (protocol_version == 0)
60+
{
61+
throw UrException("Protocol version for RTDE communication could not be established. Robot didn't accept any of "
62+
"the suggested versions.");
63+
}
64+
}
65+
LOG_INFO("Negotiated RTDE protocol version to %hu.", protocol_version);
5566
parser_.setProtocolVersion(protocol_version);
5667

5768
queryURControlVersion();
@@ -70,64 +81,93 @@ bool RTDEClient::init()
7081
return true;
7182
}
7283

73-
uint16_t RTDEClient::negotiateProtocolVersion()
84+
bool RTDEClient::negotiateProtocolVersion(const uint16_t protocol_version)
7485
{
86+
static unsigned num_retries = 0;
7587
uint8_t buffer[4096];
7688
size_t size;
7789
size_t written;
78-
uint16_t protocol_version = 2;
7990
size = RequestProtocolVersionRequest::generateSerializedRequest(buffer, protocol_version);
8091
if (!stream_.write(buffer, size, written))
8192
throw UrException("Sending protocol version query to robot failed.");
93+
8294
std::unique_ptr<RTDEPackage> package;
83-
if (!pipeline_.getLatestProduct(package, std::chrono::milliseconds(1000)))
84-
throw UrException("Could not get urcontrol version from robot. This should not happen!");
85-
rtde_interface::RequestProtocolVersion* tmp_version =
86-
dynamic_cast<rtde_interface::RequestProtocolVersion*>(package.get());
87-
if (!tmp_version->accepted_)
95+
while (num_retries < MAX_REQUEST_RETRIES)
8896
{
89-
protocol_version = 1;
90-
size = RequestProtocolVersionRequest::generateSerializedRequest(buffer, protocol_version);
91-
if (!stream_.write(buffer, size, written))
92-
throw UrException("Sending protocol version query to robot failed.");
9397
if (!pipeline_.getLatestProduct(package, std::chrono::milliseconds(1000)))
94-
throw UrException("Could not get urcontrol version from robot. This should not happen!");
95-
tmp_version = dynamic_cast<rtde_interface::RequestProtocolVersion*>(package.get());
96-
if (!tmp_version->accepted_)
9798
{
98-
throw UrException("Neither protocol version 1 nor 2 was accepted by the robot. This should not happen!");
99+
throw UrException("No answer to RTDE protocol version negotiation request was received from robot. This should "
100+
"not "
101+
"happen!");
102+
}
103+
104+
if (rtde_interface::RequestProtocolVersion* tmp_version =
105+
dynamic_cast<rtde_interface::RequestProtocolVersion*>(package.get()))
106+
{
107+
// Reset the num_tries variable in case we have to try with another protocol version.
108+
num_retries = 0;
109+
return tmp_version->accepted_;
110+
}
111+
else
112+
{
113+
std::stringstream ss;
114+
ss << "Did not receive protocol negotiation answer from robot. Message received instead: " << std::endl
115+
<< package->toString() << ". Retrying...";
116+
num_retries++;
117+
LOG_WARN("%s", ss.str().c_str());
99118
}
100119
}
101-
return protocol_version;
120+
std::stringstream ss;
121+
ss << "Could not negotiate RTDE protocol version after " << MAX_REQUEST_RETRIES
122+
<< " tries. Please check the output of the "
123+
"negotiation attempts above to get a hint what could be wrong.";
124+
throw UrException(ss.str());
102125
}
103126

104127
void RTDEClient::queryURControlVersion()
105128
{
129+
static unsigned num_retries = 0;
106130
uint8_t buffer[4096];
107131
size_t size;
108132
size_t written;
109-
std::unique_ptr<RTDEPackage> package;
110133
size = GetUrcontrolVersionRequest::generateSerializedRequest(buffer);
111134
if (!stream_.write(buffer, size, written))
112135
throw UrException("Sending urcontrol version query request to robot failed.");
113-
if (!pipeline_.getLatestProduct(package, std::chrono::milliseconds(1000)))
114-
throw UrException("Could not get urcontrol version from robot. This should not happen!");
115-
rtde_interface::GetUrcontrolVersion* tmp_urcontrol_version =
116-
dynamic_cast<rtde_interface::GetUrcontrolVersion*>(package.get());
117136

118-
if (tmp_urcontrol_version == nullptr)
137+
std::unique_ptr<RTDEPackage> package;
138+
while (num_retries < MAX_REQUEST_RETRIES)
119139
{
120-
throw UrException("Could not get urcontrol version from robot. This should not happen!");
140+
if (!pipeline_.getLatestProduct(package, std::chrono::milliseconds(1000)))
141+
throw UrException("No answer to urcontrol version query was received from robot. This should not happen!");
142+
143+
if (rtde_interface::GetUrcontrolVersion* tmp_urcontrol_version =
144+
dynamic_cast<rtde_interface::GetUrcontrolVersion*>(package.get()))
145+
{
146+
urcontrol_version_ = tmp_urcontrol_version->version_information_;
147+
return;
148+
}
149+
else
150+
{
151+
std::stringstream ss;
152+
ss << "Did not receive protocol negotiation answer from robot. Message received instead: " << std::endl
153+
<< package->toString() << ". Retrying...";
154+
num_retries++;
155+
LOG_WARN("%s", ss.str().c_str());
156+
}
121157
}
122-
urcontrol_version_ = tmp_urcontrol_version->version_information_;
158+
std::stringstream ss;
159+
ss << "Could not query urcontrol version after " << MAX_REQUEST_RETRIES
160+
<< " tries. Please check the output of the "
161+
"negotiation attempts above to get a hint what could be wrong.";
162+
throw UrException(ss.str());
123163
}
124164

125165
void RTDEClient::setupOutputs(const uint16_t protocol_version)
126166
{
167+
static unsigned num_retries = 0;
127168
size_t size;
128169
size_t written;
129170
uint8_t buffer[4096];
130-
std::unique_ptr<RTDEPackage> package;
131171
LOG_INFO("Setting up RTDE communication with frequency %f", max_frequency_);
132172
if (protocol_version == 2)
133173
{
@@ -141,71 +181,112 @@ void RTDEClient::setupOutputs(const uint16_t protocol_version)
141181
// Send output recipe to robot
142182
if (!stream_.write(buffer, size, written))
143183
throw UrException("Could not send RTDE output recipe to robot.");
144-
if (!pipeline_.getLatestProduct(package, std::chrono::milliseconds(1000)))
184+
185+
std::unique_ptr<RTDEPackage> package;
186+
while (num_retries < MAX_REQUEST_RETRIES)
145187
{
146-
throw UrException("Did not receive confirmation on RTDE output recipe.");
147-
}
188+
if (!pipeline_.getLatestProduct(package, std::chrono::milliseconds(1000)))
189+
{
190+
throw UrException("Did not receive confirmation on RTDE output recipe.");
191+
}
148192

149-
rtde_interface::ControlPackageSetupOutputs* tmp_output =
150-
dynamic_cast<rtde_interface::ControlPackageSetupOutputs*>(package.get());
193+
if (rtde_interface::ControlPackageSetupOutputs* tmp_output =
194+
dynamic_cast<rtde_interface::ControlPackageSetupOutputs*>(package.get()))
151195

152-
std::vector<std::string> variable_types = splitVariableTypes(tmp_output->variable_types_);
153-
assert(output_recipe_.size() == variable_types.size());
154-
for (std::size_t i = 0; i < variable_types.size(); ++i)
155-
{
156-
LOG_DEBUG("%s confirmed as datatype: %s", output_recipe_[i].c_str(), variable_types[i].c_str());
157-
if (variable_types[i] == "NOT_FOUND")
158196
{
159-
std::string message = "Variable '" + output_recipe_[i] +
160-
"' not recognized by the robot. Probably your output recipe contains errors";
161-
throw UrException(message);
197+
std::vector<std::string> variable_types = splitVariableTypes(tmp_output->variable_types_);
198+
assert(output_recipe_.size() == variable_types.size());
199+
for (std::size_t i = 0; i < variable_types.size(); ++i)
200+
{
201+
LOG_DEBUG("%s confirmed as datatype: %s", output_recipe_[i].c_str(), variable_types[i].c_str());
202+
return;
203+
if (variable_types[i] == "NOT_FOUND")
204+
{
205+
std::string message = "Variable '" + output_recipe_[i] +
206+
"' not recognized by the robot. Probably your output recipe contains errors";
207+
throw UrException(message);
208+
}
209+
}
210+
}
211+
else
212+
{
213+
std::stringstream ss;
214+
ss << "Did not receive answer to RTDE output setup. Message received instead: " << std::endl
215+
<< package->toString() << ". Retrying...";
216+
num_retries++;
217+
LOG_WARN("%s", ss.str().c_str());
162218
}
163219
}
220+
std::stringstream ss;
221+
ss << "Could not setup RTDE outputs after " << MAX_REQUEST_RETRIES
222+
<< " tries. Please check the output of the "
223+
"negotiation attempts above to get a hint what could be wrong.";
224+
throw UrException(ss.str());
164225
}
165226

166227
void RTDEClient::setupInputs()
167228
{
229+
static unsigned num_retries = 0;
168230
size_t size;
169231
size_t written;
170232
uint8_t buffer[4096];
171-
std::unique_ptr<RTDEPackage> package;
172233
size = ControlPackageSetupInputsRequest::generateSerializedRequest(buffer, input_recipe_);
173234
if (!stream_.write(buffer, size, written))
174235
throw UrException("Could not send RTDE input recipe to robot.");
175-
if (!pipeline_.getLatestProduct(package, std::chrono::milliseconds(1000)))
176-
throw UrException("Did not receive confirmation on RTDE input recipe.");
177-
rtde_interface::ControlPackageSetupInputs* tmp_input =
178-
dynamic_cast<rtde_interface::ControlPackageSetupInputs*>(package.get());
179-
if (tmp_input == nullptr)
180-
{
181-
throw UrException("Could not setup RTDE inputs.");
182-
}
183236

184-
std::vector<std::string> variable_types = splitVariableTypes(tmp_input->variable_types_);
185-
assert(input_recipe_.size() == variable_types.size());
186-
for (std::size_t i = 0; i < variable_types.size(); ++i)
237+
std::unique_ptr<RTDEPackage> package;
238+
while (num_retries < MAX_REQUEST_RETRIES)
187239
{
188-
LOG_DEBUG("%s confirmed as datatype: %s", input_recipe_[i].c_str(), variable_types[i].c_str());
189-
if (variable_types[i] == "NOT_FOUND")
240+
if (!pipeline_.getLatestProduct(package, std::chrono::milliseconds(1000)))
241+
throw UrException("Did not receive confirmation on RTDE input recipe.");
242+
243+
if (rtde_interface::ControlPackageSetupInputs* tmp_input =
244+
dynamic_cast<rtde_interface::ControlPackageSetupInputs*>(package.get()))
245+
190246
{
191-
std::string message =
192-
"Variable '" + input_recipe_[i] + "' not recognized by the robot. Probably your input recipe contains errors";
193-
throw UrException(message);
247+
std::vector<std::string> variable_types = splitVariableTypes(tmp_input->variable_types_);
248+
assert(input_recipe_.size() == variable_types.size());
249+
for (std::size_t i = 0; i < variable_types.size(); ++i)
250+
{
251+
LOG_DEBUG("%s confirmed as datatype: %s", input_recipe_[i].c_str(), variable_types[i].c_str());
252+
if (variable_types[i] == "NOT_FOUND")
253+
{
254+
std::string message = "Variable '" + input_recipe_[i] +
255+
"' not recognized by the robot. Probably your input recipe contains errors";
256+
throw UrException(message);
257+
}
258+
else if (variable_types[i] == "IN_USE")
259+
{
260+
std::string message = "Variable '" + input_recipe_[i] +
261+
"' is currently controlled by another RTDE client. The input recipe can't be used as "
262+
"configured";
263+
throw UrException(message);
264+
}
265+
}
266+
267+
writer_.init(tmp_input->input_recipe_id_);
268+
269+
return;
194270
}
195-
else if (variable_types[i] == "IN_USE")
271+
else
196272
{
197-
std::string message = "Variable '" + input_recipe_[i] +
198-
"' is currently controlled by another RTDE client. The input recipe can't be used as "
199-
"configured";
200-
throw UrException(message);
273+
std::stringstream ss;
274+
ss << "Did not receive answer to RTDE input setup. Message received instead: " << std::endl
275+
<< package->toString() << ". Retrying...";
276+
num_retries++;
277+
LOG_WARN("%s", ss.str().c_str());
201278
}
202279
}
203-
204-
writer_.init(tmp_input->input_recipe_id_);
280+
std::stringstream ss;
281+
ss << "Could not setup RTDE inputs after " << MAX_REQUEST_RETRIES
282+
<< " tries. Please check the output of the "
283+
"negotiation attempts above to get a hint what could be wrong.";
284+
throw UrException(ss.str());
205285
}
206286

207287
bool RTDEClient::start()
208288
{
289+
static unsigned num_retries = 0;
209290
uint8_t buffer[4096];
210291
size_t size;
211292
size_t written;
@@ -214,12 +295,30 @@ bool RTDEClient::start()
214295
std::unique_ptr<RTDEPackage> package;
215296
if (!stream_.write(buffer, size, written))
216297
throw UrException("Sending RTDE start command failed!");
217-
if (!pipeline_.getLatestProduct(package, std::chrono::milliseconds(1000)))
218-
throw UrException("Could not get response to RTDE communication start request from robot. This should not "
219-
"happen!");
220-
rtde_interface::ControlPackageStart* tmp = dynamic_cast<rtde_interface::ControlPackageStart*>(package.get());
221-
return tmp->accepted_;
298+
while (num_retries < MAX_REQUEST_RETRIES)
299+
{
300+
if (!pipeline_.getLatestProduct(package, std::chrono::milliseconds(1000)))
301+
throw UrException("Could not get response to RTDE communication start request from robot. This should not "
302+
"happen!");
303+
if (rtde_interface::ControlPackageStart* tmp = dynamic_cast<rtde_interface::ControlPackageStart*>(package.get()))
304+
{
305+
return tmp->accepted_;
306+
}
307+
else
308+
{
309+
std::stringstream ss;
310+
ss << "Did not receive answer to RTDE start request. Message received instead: " << std::endl
311+
<< package->toString() << ". Retrying...";
312+
LOG_WARN("%s", ss.str().c_str());
313+
}
314+
}
315+
std::stringstream ss;
316+
ss << "Could not start RTDE communication after " << MAX_REQUEST_RETRIES
317+
<< " tries. Please check the output of the "
318+
"negotiation attempts above to get a hint what could be wrong.";
319+
throw UrException(ss.str());
222320
}
321+
223322
std::vector<std::string> RTDEClient::readRecipe(const std::string& recipe_file)
224323
{
225324
std::vector<std::string> recipe;

0 commit comments

Comments
 (0)