Skip to content

Commit 5b63dc0

Browse files
Make the RTDE output recipe adaptation opt-in
1 parent dc1e771 commit 5b63dc0

File tree

5 files changed

+77
-26
lines changed

5 files changed

+77
-26
lines changed

include/ur_client_library/rtde/rtde_client.h

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -103,10 +103,13 @@ class RTDEClient
103103
* \param notifier The notifier to use in the pipeline
104104
* \param output_recipe_file Path to the file containing the output recipe
105105
* \param input_recipe_file Path to the file containing the input recipe
106+
* \param ignore_unavailable_outputs Configure the behaviour when a variable of the output recipe is not available
107+
* from the robot: output is silently ignored if true, a UrException is raised otherwise.
106108
* \param target_frequency Frequency to run at. Defaults to 0.0 which means maximum frequency.
107109
*/
108110
RTDEClient(std::string robot_ip, comm::INotifier& notifier, const std::string& output_recipe_file,
109-
const std::string& input_recipe_file, double target_frequency = 0.0);
111+
const std::string& input_recipe_file, bool ignore_unavailable_outputs = false,
112+
double target_frequency = 0.0);
110113

111114
/*!
112115
* \brief Creates a new RTDEClient object, including a used URStream and Pipeline to handle the
@@ -116,10 +119,13 @@ class RTDEClient
116119
* \param notifier The notifier to use in the pipeline
117120
* \param output_recipe Vector containing the output recipe
118121
* \param input_recipe Vector containing the input recipe
122+
* \param ignore_unavailable_outputs Configure the behaviour when a variable of the output recipe is not available
123+
* from the robot: output is silently ignored if true, a UrException is raised otherwise.
119124
* \param target_frequency Frequency to run at. Defaults to 0.0 which means maximum frequency.
120125
*/
121126
RTDEClient(std::string robot_ip, comm::INotifier& notifier, const std::vector<std::string>& output_recipe,
122-
const std::vector<std::string>& input_recipe, double target_frequency = 0.0);
127+
const std::vector<std::string>& input_recipe, bool ignore_available_outputs = false,
128+
double target_frequency = 0.0);
123129
~RTDEClient();
124130
/*!
125131
* \brief Sets up RTDE communication with the robot. The handshake includes negotiation of the
@@ -208,10 +214,11 @@ class RTDEClient
208214
{
209215
return output_recipe_;
210216
}
211-
217+
212218
private:
213219
comm::URStream<RTDEPackage> stream_;
214220
std::vector<std::string> output_recipe_;
221+
bool ignore_unavailable_outputs_;
215222
std::vector<std::string> input_recipe_;
216223
RTDEParser parser_;
217224
std::unique_ptr<comm::URProducer<RTDEPackage>> prod_;

include/ur_client_library/ur/ur_driver.h

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -605,10 +605,13 @@ class UrDriver
605605
*
606606
* \param output_recipe Vector containing the output recipe
607607
* \param input_recipe Vector containing the input recipe
608-
* \param target_frequency Frequency to run the RTDE client at. Defaults to 0.0 which means maximum frequency.
608+
* \param ignore_unavailable_outputs Configure the behaviour when a variable of the output recipe is not available
609+
* from the robot: output is silently ignored if true, a UrException is raised otherwise.
610+
* \param target_frequency
611+
* Frequency to run the RTDE client at. Defaults to 0.0 which means maximum frequency.
609612
*/
610613
void resetRTDEClient(const std::vector<std::string>& output_recipe, const std::vector<std::string>& input_recipe,
611-
double target_frequency = 0.0);
614+
bool ignore_unavailable_outputs = false, double target_frequency = 0.0);
612615

613616
/**
614617
* \brief Reset the RTDE client. As during initialization the driver will start RTDE communication
@@ -620,10 +623,12 @@ class UrDriver
620623
*
621624
* \param output_recipe_filename Filename where the output recipe is stored in.
622625
* \param input_recipe_filename Filename where the input recipe is stored in.
626+
* \param ignore_unavailable_outputs Configure the behaviour when a variable of the output recipe is not available
627+
* from the robot: output is silently ignored if true, a UrException is raised otherwise.
623628
* \param target_frequency Frequency to run the RTDE client at. Defaults to 0.0 which means maximum frequency.
624629
*/
625630
void resetRTDEClient(const std::string& output_recipe_filename, const std::string& input_recipe_filename,
626-
double target_frequency = 0.0);
631+
bool ignore_unavailable_outputs = false, double target_frequency = 0.0);
627632

628633
private:
629634
static std::string readScriptFile(const std::string& filename);

src/rtde/rtde_client.cpp

Lines changed: 39 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -35,9 +35,10 @@ namespace urcl
3535
namespace rtde_interface
3636
{
3737
RTDEClient::RTDEClient(std::string robot_ip, comm::INotifier& notifier, const std::string& output_recipe_file,
38-
const std::string& input_recipe_file, double target_frequency)
38+
const std::string& input_recipe_file, bool ignore_unavailable_outputs, double target_frequency)
3939
: stream_(robot_ip, UR_RTDE_PORT)
4040
, output_recipe_(ensureTimestampIsPresent(readRecipe(output_recipe_file)))
41+
, ignore_unavailable_outputs_(ignore_unavailable_outputs)
4142
, input_recipe_(readRecipe(input_recipe_file))
4243
, parser_(output_recipe_)
4344
, prod_(std::make_unique<comm::URProducer<RTDEPackage>>(stream_, parser_))
@@ -51,9 +52,11 @@ RTDEClient::RTDEClient(std::string robot_ip, comm::INotifier& notifier, const st
5152
}
5253

5354
RTDEClient::RTDEClient(std::string robot_ip, comm::INotifier& notifier, const std::vector<std::string>& output_recipe,
54-
const std::vector<std::string>& input_recipe, double target_frequency)
55+
const std::vector<std::string>& input_recipe, bool ignore_unavailable_outputs,
56+
double target_frequency)
5557
: stream_(robot_ip, UR_RTDE_PORT)
5658
, output_recipe_(ensureTimestampIsPresent(output_recipe))
59+
, ignore_unavailable_outputs_(ignore_unavailable_outputs)
5760
, input_recipe_(input_recipe)
5861
, parser_(output_recipe_)
5962
, prod_(std::make_unique<comm::URProducer<RTDEPackage>>(stream_, parser_))
@@ -251,11 +254,12 @@ void RTDEClient::queryURControlVersion()
251254
throw UrException(ss.str());
252255
}
253256

254-
void RTDEClient::resetOutputRecipe(const std::vector<std::string> new_recipe) {
257+
void RTDEClient::resetOutputRecipe(const std::vector<std::string> new_recipe)
258+
{
255259
prod_->teardownProducer();
256260
disconnect();
257261

258-
output_recipe_.assign(new_recipe.begin(), new_recipe.end());
262+
output_recipe_.assign(new_recipe.begin(), new_recipe.end());
259263
parser_ = RTDEParser(output_recipe_);
260264
prod_ = std::make_unique<comm::URProducer<RTDEPackage>>(stream_, parser_);
261265
pipeline_ = std::make_unique<comm::Pipeline<RTDEPackage>>(*prod_, PIPELINE_NAME, notifier_, true);
@@ -308,33 +312,52 @@ void RTDEClient::setupOutputs(const uint16_t protocol_version)
308312
{
309313
std::vector<std::string> variable_types = splitVariableTypes(tmp_output->variable_types_);
310314
std::vector<std::string> available_variables;
315+
std::vector<std::string> unavailable_variables;
311316
assert(output_recipe_.size() == variable_types.size());
312317
for (std::size_t i = 0; i < variable_types.size(); ++i)
313318
{
314319
const std::string variable_name = output_recipe_[i];
315320
URCL_LOG_DEBUG("%s confirmed as datatype: %s", variable_name.c_str(), variable_types[i].c_str());
316-
321+
317322
if (variable_types[i] == "NOT_FOUND")
318323
{
319-
const std::string message = "Variable '" + variable_name + "' not recognized by the robot. "
320-
"Either your output recipe contains errors or the urcontrol version "
321-
"does not support it. It will be removed from the output recipe.";
322-
URCL_LOG_WARN("%s", message.c_str());
323-
}
324-
else
324+
unavailable_variables.push_back(variable_name);
325+
}
326+
else
325327
{
326328
available_variables.push_back(variable_name);
327329
}
328330
}
329331

330-
if (available_variables.size() == output_recipe_.size()) {
332+
if (!unavailable_variables.empty())
333+
{
334+
std::stringstream error_message;
335+
error_message << "The following variables are not recognized by the robot: ";
336+
std::for_each(unavailable_variables.begin(), unavailable_variables.end(),
337+
[&error_message](const std::string& variable_name) { error_message << variable_name << " "; });
338+
error_message << ". Either your output recipe contains errors "
339+
"or the urcontrol version does not support "
340+
"them.";
341+
342+
if (ignore_unavailable_outputs_)
343+
{
344+
error_message << " They will be removed from the output recipe.";
345+
URCL_LOG_WARN("%s", error_message.str().c_str());
346+
347+
// Some variables are not available so retry setting up the communication with a stripped-down output recipe
348+
resetOutputRecipe(available_variables);
349+
}
350+
else
351+
{
352+
URCL_LOG_ERROR("%s", error_message.str().c_str());
353+
throw UrException(error_message.str());
354+
}
355+
}
356+
else
357+
{
331358
// All variables are accounted for in the RTDE package
332359
return;
333360
}
334-
335-
// Some variables are not available so retry setting up the communication with a stripped-down output recipe
336-
resetOutputRecipe(available_variables);
337-
return;
338361
}
339362
else
340363
{

src/ur/ur_driver.cpp

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -691,18 +691,19 @@ void UrDriver::setKeepaliveCount(const uint32_t count)
691691
}
692692

693693
void UrDriver::resetRTDEClient(const std::vector<std::string>& output_recipe,
694-
const std::vector<std::string>& input_recipe, double target_frequency)
694+
const std::vector<std::string>& input_recipe, bool ignore_unavailable_outputs,
695+
double target_frequency)
695696
{
696697
rtde_client_.reset(
697698
new rtde_interface::RTDEClient(robot_ip_, notifier_, output_recipe, input_recipe, target_frequency));
698699
initRTDE();
699700
}
700701

701702
void UrDriver::resetRTDEClient(const std::string& output_recipe_filename, const std::string& input_recipe_filename,
702-
double target_frequency)
703+
bool ignore_unavailable_outputs, double target_frequency)
703704
{
704705
rtde_client_.reset(new rtde_interface::RTDEClient(robot_ip_, notifier_, output_recipe_filename, input_recipe_filename,
705-
target_frequency));
706+
ignore_unavailable_outputs, target_frequency));
706707
initRTDE();
707708
}
708709

tests/test_rtde_client.cpp

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -373,7 +373,9 @@ TEST_F(RTDEClientTest, check_all_rtde_output_variables_exist)
373373
{
374374
client_->init();
375375

376-
client_.reset(new rtde_interface::RTDEClient(ROBOT_IP, notifier_, exhaustive_output_recipe_file_, input_recipe_file_));
376+
// Ignore unknown output variables to account for variables not available in old urcontrol versions.
377+
client_.reset(
378+
new rtde_interface::RTDEClient(ROBOT_IP, notifier_, exhaustive_output_recipe_file_, input_recipe_file_, true));
377379

378380
EXPECT_NO_THROW(client_->init());
379381
client_->start();
@@ -394,6 +396,19 @@ TEST_F(RTDEClientTest, check_all_rtde_output_variables_exist)
394396
client_->pause();
395397
}
396398

399+
TEST_F(RTDEClientTest, check_unknown_rtde_output_variable)
400+
{
401+
client_->init();
402+
403+
std::vector<std::string> incorrect_output_recipe = client_->getOutputRecipe();
404+
incorrect_output_recipe.push_back("unknown_rtde_variable");
405+
406+
client_.reset(
407+
new rtde_interface::RTDEClient(ROBOT_IP, notifier_, incorrect_output_recipe, resources_input_recipe_, false));
408+
409+
EXPECT_THROW(client_->init(), UrException);
410+
}
411+
397412
int main(int argc, char* argv[])
398413
{
399414
::testing::InitGoogleTest(&argc, argv);

0 commit comments

Comments
 (0)