@@ -35,13 +35,15 @@ namespace urcl
3535namespace rtde_interface
3636{
3737RTDEClient::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, double target_frequency, bool ignore_unavailable_outputs )
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_)
43- , prod_(stream_, parser_)
44- , pipeline_(prod_, PIPELINE_NAME, notifier, true )
44+ , prod_(std::make_unique<comm::URProducer<RTDEPackage>>(stream_, parser_))
45+ , notifier_(notifier)
46+ , pipeline_(std::make_unique<comm::Pipeline<RTDEPackage>>(*prod_, PIPELINE_NAME, notifier, true ))
4547 , writer_(&stream_, input_recipe_)
4648 , max_frequency_(URE_MAX_FREQUENCY)
4749 , target_frequency_(target_frequency)
@@ -50,13 +52,16 @@ RTDEClient::RTDEClient(std::string robot_ip, comm::INotifier& notifier, const st
5052}
5153
5254RTDEClient::RTDEClient (std::string robot_ip, comm::INotifier& notifier, const std::vector<std::string>& output_recipe,
53- const std::vector<std::string>& input_recipe, double target_frequency)
55+ const std::vector<std::string>& input_recipe, double target_frequency,
56+ bool ignore_unavailable_outputs)
5457 : stream_(robot_ip, UR_RTDE_PORT)
5558 , output_recipe_(ensureTimestampIsPresent(output_recipe))
59+ , ignore_unavailable_outputs_(ignore_unavailable_outputs)
5660 , input_recipe_(input_recipe)
5761 , parser_(output_recipe_)
58- , prod_(stream_, parser_)
59- , pipeline_(prod_, PIPELINE_NAME, notifier, true )
62+ , prod_(std::make_unique<comm::URProducer<RTDEPackage>>(stream_, parser_))
63+ , notifier_(notifier)
64+ , pipeline_(std::make_unique<comm::Pipeline<RTDEPackage>>(*prod_, PIPELINE_NAME, notifier, true ))
6065 , writer_(&stream_, input_recipe_)
6166 , max_frequency_(URE_MAX_FREQUENCY)
6267 , target_frequency_(target_frequency)
@@ -96,8 +101,8 @@ void RTDEClient::setupCommunication(const size_t max_num_tries, const std::chron
96101{
97102 client_state_ = ClientState::INITIALIZING;
98103 // A running pipeline is needed inside setup
99- pipeline_. init (max_num_tries, reconnection_time);
100- pipeline_. run ();
104+ pipeline_-> init (max_num_tries, reconnection_time);
105+ pipeline_-> run ();
101106
102107 uint16_t protocol_version = MAX_RTDE_PROTOCOL_VERSION;
103108 while (!negotiateProtocolVersion (protocol_version) && client_state_ == ClientState::INITIALIZING)
@@ -151,7 +156,7 @@ void RTDEClient::setupCommunication(const size_t max_num_tries, const std::chron
151156 return ;
152157
153158 // We finished communication for now
154- pipeline_. stop ();
159+ pipeline_-> stop ();
155160 client_state_ = ClientState::INITIALIZED;
156161}
157162
@@ -174,7 +179,7 @@ bool RTDEClient::negotiateProtocolVersion(const uint16_t protocol_version)
174179 while (num_retries < MAX_REQUEST_RETRIES)
175180 {
176181 std::unique_ptr<RTDEPackage> package;
177- if (!pipeline_. getLatestProduct (package, std::chrono::milliseconds (1000 )))
182+ if (!pipeline_-> getLatestProduct (package, std::chrono::milliseconds (1000 )))
178183 {
179184 URCL_LOG_ERROR (" failed to get package from rtde interface, disconnecting" );
180185 disconnect ();
@@ -220,7 +225,7 @@ void RTDEClient::queryURControlVersion()
220225 std::unique_ptr<RTDEPackage> package;
221226 while (num_retries < MAX_REQUEST_RETRIES)
222227 {
223- if (!pipeline_. getLatestProduct (package, std::chrono::milliseconds (1000 )))
228+ if (!pipeline_-> getLatestProduct (package, std::chrono::milliseconds (1000 )))
224229 {
225230 URCL_LOG_ERROR (" No answer to urcontrol version query was received from robot, disconnecting" );
226231 disconnect ();
@@ -249,39 +254,52 @@ void RTDEClient::queryURControlVersion()
249254 throw UrException (ss.str ());
250255}
251256
257+ void RTDEClient::resetOutputRecipe (const std::vector<std::string> new_recipe)
258+ {
259+ prod_->teardownProducer ();
260+ disconnect ();
261+
262+ output_recipe_.assign (new_recipe.begin (), new_recipe.end ());
263+ parser_ = RTDEParser (output_recipe_);
264+ prod_ = std::make_unique<comm::URProducer<RTDEPackage>>(stream_, parser_);
265+ pipeline_ = std::make_unique<comm::Pipeline<RTDEPackage>>(*prod_, PIPELINE_NAME, notifier_, true );
266+ }
267+
252268void RTDEClient::setupOutputs (const uint16_t protocol_version)
253269{
254270 unsigned int num_retries = 0 ;
255271 size_t size;
256272 size_t written;
257273 uint8_t buffer[8192 ];
258274 URCL_LOG_INFO (" Setting up RTDE communication with frequency %f" , target_frequency_);
259- if (protocol_version == 2 )
260- {
261- size = ControlPackageSetupOutputsRequest::generateSerializedRequest (buffer, target_frequency_, output_recipe_);
262- }
263- else
275+
276+ while (num_retries < MAX_REQUEST_RETRIES)
264277 {
265- if (target_frequency_ != max_frequency_)
278+ URCL_LOG_DEBUG (" Sending output recipe" );
279+ if (protocol_version == 2 )
266280 {
267- URCL_LOG_WARN (" It is not possible to set a target frequency when using protocol version 1. A frequency "
268- " equivalent to the maximum frequency will be used instead." );
281+ size = ControlPackageSetupOutputsRequest::generateSerializedRequest (buffer, target_frequency_, output_recipe_);
282+ }
283+ else
284+ {
285+ if (target_frequency_ != max_frequency_)
286+ {
287+ URCL_LOG_WARN (" It is not possible to set a target frequency when using protocol version 1. A frequency "
288+ " equivalent to the maximum frequency will be used instead." );
289+ }
290+ size = ControlPackageSetupOutputsRequest::generateSerializedRequest (buffer, output_recipe_);
269291 }
270- size = ControlPackageSetupOutputsRequest::generateSerializedRequest (buffer, output_recipe_);
271- }
272292
273- // Send output recipe to robot
274- if (!stream_.write (buffer, size, written))
275- {
276- URCL_LOG_ERROR (" Could not send RTDE output recipe to robot, disconnecting" );
277- disconnect ();
278- return ;
279- }
293+ // Send output recipe to robot
294+ if (!stream_.write (buffer, size, written))
295+ {
296+ URCL_LOG_ERROR (" Could not send RTDE output recipe to robot, disconnecting" );
297+ disconnect ();
298+ return ;
299+ }
280300
281- while (num_retries < MAX_REQUEST_RETRIES)
282- {
283301 std::unique_ptr<RTDEPackage> package;
284- if (!pipeline_. getLatestProduct (package, std::chrono::milliseconds (1000 )))
302+ if (!pipeline_-> getLatestProduct (package, std::chrono::milliseconds (1000 )))
285303 {
286304 URCL_LOG_ERROR (" Did not receive confirmation on RTDE output recipe, disconnecting" );
287305 disconnect ();
@@ -293,18 +311,53 @@ void RTDEClient::setupOutputs(const uint16_t protocol_version)
293311
294312 {
295313 std::vector<std::string> variable_types = splitVariableTypes (tmp_output->variable_types_ );
314+ std::vector<std::string> available_variables;
315+ std::vector<std::string> unavailable_variables;
296316 assert (output_recipe_.size () == variable_types.size ());
297317 for (std::size_t i = 0 ; i < variable_types.size (); ++i)
298318 {
299- URCL_LOG_DEBUG (" %s confirmed as datatype: %s" , output_recipe_[i].c_str (), variable_types[i].c_str ());
319+ const std::string variable_name = output_recipe_[i];
320+ URCL_LOG_DEBUG (" %s confirmed as datatype: %s" , variable_name.c_str (), variable_types[i].c_str ());
321+
300322 if (variable_types[i] == " NOT_FOUND" )
301323 {
302- std::string message = " Variable '" + output_recipe_[i] +
303- " ' not recognized by the robot. Probably your output recipe contains errors" ;
304- throw UrException (message);
324+ unavailable_variables.push_back (variable_name);
325+ }
326+ else
327+ {
328+ available_variables.push_back (variable_name);
305329 }
306330 }
307- return ;
331+
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+ {
358+ // All variables are accounted for in the RTDE package
359+ return ;
360+ }
308361 }
309362 else
310363 {
@@ -339,7 +392,7 @@ void RTDEClient::setupInputs()
339392 while (num_retries < MAX_REQUEST_RETRIES)
340393 {
341394 std::unique_ptr<RTDEPackage> package;
342- if (!pipeline_. getLatestProduct (package, std::chrono::milliseconds (1000 )))
395+ if (!pipeline_-> getLatestProduct (package, std::chrono::milliseconds (1000 )))
343396 {
344397 URCL_LOG_ERROR (" Did not receive confirmation on RTDE input recipe, disconnecting" );
345398 disconnect ();
@@ -395,7 +448,7 @@ void RTDEClient::disconnect()
395448 if (client_state_ > ClientState::UNINITIALIZED)
396449 {
397450 sendPause ();
398- pipeline_. stop ();
451+ pipeline_-> stop ();
399452 stream_.disconnect ();
400453 }
401454 client_state_ = ClientState::UNINITIALIZED;
@@ -421,7 +474,7 @@ bool RTDEClient::isRobotBooted()
421474 {
422475 // Set timeout based on target frequency, to make sure that reading doesn't timeout
423476 int timeout = static_cast <int >((1 / target_frequency_) * 1000 ) * 10 ;
424- if (pipeline_. getLatestProduct (package, std::chrono::milliseconds (timeout)))
477+ if (pipeline_-> getLatestProduct (package, std::chrono::milliseconds (timeout)))
425478 {
426479 rtde_interface::DataPackage* tmp_input = dynamic_cast <rtde_interface::DataPackage*>(package.get ());
427480 tmp_input->getData (" timestamp" , timestamp);
@@ -451,7 +504,7 @@ bool RTDEClient::start()
451504 return false ;
452505 }
453506
454- pipeline_. run ();
507+ pipeline_-> run ();
455508
456509 if (sendStart ())
457510 {
@@ -501,7 +554,7 @@ bool RTDEClient::sendStart()
501554 unsigned int num_retries = 0 ;
502555 while (num_retries < MAX_REQUEST_RETRIES)
503556 {
504- if (!pipeline_. getLatestProduct (package, std::chrono::milliseconds (1000 )))
557+ if (!pipeline_-> getLatestProduct (package, std::chrono::milliseconds (1000 )))
505558 {
506559 URCL_LOG_ERROR (" Could not get response to RTDE communication start request from robot" );
507560 return false ;
@@ -543,7 +596,7 @@ bool RTDEClient::sendPause()
543596 int seconds = 5 ;
544597 while (std::chrono::steady_clock::now () - start < std::chrono::seconds (seconds))
545598 {
546- if (!pipeline_. getLatestProduct (package, std::chrono::milliseconds (1000 )))
599+ if (!pipeline_-> getLatestProduct (package, std::chrono::milliseconds (1000 )))
547600 {
548601 URCL_LOG_ERROR (" Could not get response to RTDE communication pause request from robot" );
549602 return false ;
@@ -605,7 +658,7 @@ std::vector<std::string> RTDEClient::ensureTimestampIsPresent(const std::vector<
605658std::unique_ptr<rtde_interface::DataPackage> RTDEClient::getDataPackage (std::chrono::milliseconds timeout)
606659{
607660 std::unique_ptr<RTDEPackage> urpackage;
608- if (pipeline_. getLatestProduct (urpackage, timeout))
661+ if (pipeline_-> getLatestProduct (urpackage, timeout))
609662 {
610663 rtde_interface::DataPackage* tmp = dynamic_cast <rtde_interface::DataPackage*>(urpackage.get ());
611664 if (tmp != nullptr )
0 commit comments