Skip to content

Commit dc1e771

Browse files
Adapt RTDE output recipe based on robot response
1 parent d3baa8b commit dc1e771

File tree

5 files changed

+434
-422
lines changed

5 files changed

+434
-422
lines changed

include/ur_client_library/comm/pipeline.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,8 @@ template <typename T>
4343
class IConsumer
4444
{
4545
public:
46+
virtual ~IConsumer() = default;
47+
4648
/*!
4749
* \brief Set-up functionality of the consumer.
4850
*/
@@ -170,6 +172,8 @@ template <typename T>
170172
class IProducer
171173
{
172174
public:
175+
virtual ~IProducer() = default;
176+
173177
/*!
174178
* \brief Set-up functionality of the producers.
175179
*

include/ur_client_library/rtde/rtde_client.h

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@
2929
#ifndef UR_CLIENT_LIBRARY_RTDE_CLIENT_H_INCLUDED
3030
#define UR_CLIENT_LIBRARY_RTDE_CLIENT_H_INCLUDED
3131

32+
#include <memory>
33+
3234
#include "ur_client_library/comm/pipeline.h"
3335
#include "ur_client_library/rtde/package_header.h"
3436
#include "ur_client_library/rtde/rtde_package.h"
@@ -206,14 +208,15 @@ class RTDEClient
206208
{
207209
return output_recipe_;
208210
}
209-
211+
210212
private:
211213
comm::URStream<RTDEPackage> stream_;
212214
std::vector<std::string> output_recipe_;
213215
std::vector<std::string> input_recipe_;
214216
RTDEParser parser_;
215-
comm::URProducer<RTDEPackage> prod_;
216-
comm::Pipeline<RTDEPackage> pipeline_;
217+
std::unique_ptr<comm::URProducer<RTDEPackage>> prod_;
218+
comm::INotifier notifier_;
219+
std::unique_ptr<comm::Pipeline<RTDEPackage>> pipeline_;
217220
RTDEWriter writer_;
218221

219222
VersionInformation urcontrol_version_;
@@ -241,6 +244,14 @@ class RTDEClient
241244
void setupInputs();
242245
void disconnect();
243246

247+
/*!
248+
* \brief Updates the output recipe to the given one and recreates all the objects which depend on it.
249+
* It should only be called while setting up the communication.
250+
*
251+
* \param new_recipe the new output recipe to use
252+
*/
253+
void resetOutputRecipe(const std::vector<std::string> new_recipe);
254+
244255
/*!
245256
* \brief Checks whether the robot is booted, this is done by looking at the timestamp from the robot controller, this
246257
* will show the time in seconds since the controller was started. If the timestamp is below 40, we will read from

src/rtde/rtde_client.cpp

Lines changed: 72 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,9 @@ RTDEClient::RTDEClient(std::string robot_ip, comm::INotifier& notifier, const st
4040
, output_recipe_(ensureTimestampIsPresent(readRecipe(output_recipe_file)))
4141
, input_recipe_(readRecipe(input_recipe_file))
4242
, parser_(output_recipe_)
43-
, prod_(stream_, parser_)
44-
, pipeline_(prod_, PIPELINE_NAME, notifier, true)
43+
, prod_(std::make_unique<comm::URProducer<RTDEPackage>>(stream_, parser_))
44+
, notifier_(notifier)
45+
, pipeline_(std::make_unique<comm::Pipeline<RTDEPackage>>(*prod_, PIPELINE_NAME, notifier, true))
4546
, writer_(&stream_, input_recipe_)
4647
, max_frequency_(URE_MAX_FREQUENCY)
4748
, target_frequency_(target_frequency)
@@ -55,8 +56,9 @@ RTDEClient::RTDEClient(std::string robot_ip, comm::INotifier& notifier, const st
5556
, output_recipe_(ensureTimestampIsPresent(output_recipe))
5657
, input_recipe_(input_recipe)
5758
, parser_(output_recipe_)
58-
, prod_(stream_, parser_)
59-
, pipeline_(prod_, PIPELINE_NAME, notifier, true)
59+
, prod_(std::make_unique<comm::URProducer<RTDEPackage>>(stream_, parser_))
60+
, notifier_(notifier)
61+
, pipeline_(std::make_unique<comm::Pipeline<RTDEPackage>>(*prod_, PIPELINE_NAME, notifier, true))
6062
, writer_(&stream_, input_recipe_)
6163
, max_frequency_(URE_MAX_FREQUENCY)
6264
, target_frequency_(target_frequency)
@@ -83,8 +85,8 @@ bool RTDEClient::init(const size_t max_num_tries, const std::chrono::millisecond
8385
if (client_state_ == ClientState::INITIALIZED)
8486
return true;
8587

86-
URCL_LOG_ERROR("Failed to initialize RTDE client, retrying in 10 seconds");
87-
std::this_thread::sleep_for(std::chrono::seconds(10));
88+
URCL_LOG_ERROR("Failed to initialize RTDE client, retrying in 1 seconds");
89+
std::this_thread::sleep_for(std::chrono::seconds(1));
8890
attempts++;
8991
}
9092
std::stringstream ss;
@@ -96,8 +98,8 @@ void RTDEClient::setupCommunication(const size_t max_num_tries, const std::chron
9698
{
9799
client_state_ = ClientState::INITIALIZING;
98100
// A running pipeline is needed inside setup
99-
pipeline_.init(max_num_tries, reconnection_time);
100-
pipeline_.run();
101+
pipeline_->init(max_num_tries, reconnection_time);
102+
pipeline_->run();
101103

102104
uint16_t protocol_version = MAX_RTDE_PROTOCOL_VERSION;
103105
while (!negotiateProtocolVersion(protocol_version) && client_state_ == ClientState::INITIALIZING)
@@ -151,7 +153,7 @@ void RTDEClient::setupCommunication(const size_t max_num_tries, const std::chron
151153
return;
152154

153155
// We finished communication for now
154-
pipeline_.stop();
156+
pipeline_->stop();
155157
client_state_ = ClientState::INITIALIZED;
156158
}
157159

@@ -174,7 +176,7 @@ bool RTDEClient::negotiateProtocolVersion(const uint16_t protocol_version)
174176
while (num_retries < MAX_REQUEST_RETRIES)
175177
{
176178
std::unique_ptr<RTDEPackage> package;
177-
if (!pipeline_.getLatestProduct(package, std::chrono::milliseconds(1000)))
179+
if (!pipeline_->getLatestProduct(package, std::chrono::milliseconds(1000)))
178180
{
179181
URCL_LOG_ERROR("failed to get package from rtde interface, disconnecting");
180182
disconnect();
@@ -220,7 +222,7 @@ void RTDEClient::queryURControlVersion()
220222
std::unique_ptr<RTDEPackage> package;
221223
while (num_retries < MAX_REQUEST_RETRIES)
222224
{
223-
if (!pipeline_.getLatestProduct(package, std::chrono::milliseconds(1000)))
225+
if (!pipeline_->getLatestProduct(package, std::chrono::milliseconds(1000)))
224226
{
225227
URCL_LOG_ERROR("No answer to urcontrol version query was received from robot, disconnecting");
226228
disconnect();
@@ -249,39 +251,51 @@ void RTDEClient::queryURControlVersion()
249251
throw UrException(ss.str());
250252
}
251253

254+
void RTDEClient::resetOutputRecipe(const std::vector<std::string> new_recipe) {
255+
prod_->teardownProducer();
256+
disconnect();
257+
258+
output_recipe_.assign(new_recipe.begin(), new_recipe.end());
259+
parser_ = RTDEParser(output_recipe_);
260+
prod_ = std::make_unique<comm::URProducer<RTDEPackage>>(stream_, parser_);
261+
pipeline_ = std::make_unique<comm::Pipeline<RTDEPackage>>(*prod_, PIPELINE_NAME, notifier_, true);
262+
}
263+
252264
void RTDEClient::setupOutputs(const uint16_t protocol_version)
253265
{
254266
unsigned int num_retries = 0;
255267
size_t size;
256268
size_t written;
257269
uint8_t buffer[8192];
258270
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
271+
272+
while (num_retries < MAX_REQUEST_RETRIES)
264273
{
265-
if (target_frequency_ != max_frequency_)
274+
URCL_LOG_INFO("Sending output recipe");
275+
if (protocol_version == 2)
266276
{
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.");
277+
size = ControlPackageSetupOutputsRequest::generateSerializedRequest(buffer, target_frequency_, output_recipe_);
278+
}
279+
else
280+
{
281+
if (target_frequency_ != max_frequency_)
282+
{
283+
URCL_LOG_WARN("It is not possible to set a target frequency when using protocol version 1. A frequency "
284+
"equivalent to the maximum frequency will be used instead.");
285+
}
286+
size = ControlPackageSetupOutputsRequest::generateSerializedRequest(buffer, output_recipe_);
269287
}
270-
size = ControlPackageSetupOutputsRequest::generateSerializedRequest(buffer, output_recipe_);
271-
}
272288

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-
}
289+
// Send output recipe to robot
290+
if (!stream_.write(buffer, size, written))
291+
{
292+
URCL_LOG_ERROR("Could not send RTDE output recipe to robot, disconnecting");
293+
disconnect();
294+
return;
295+
}
280296

281-
while (num_retries < MAX_REQUEST_RETRIES)
282-
{
283297
std::unique_ptr<RTDEPackage> package;
284-
if (!pipeline_.getLatestProduct(package, std::chrono::milliseconds(1000)))
298+
if (!pipeline_->getLatestProduct(package, std::chrono::milliseconds(1000)))
285299
{
286300
URCL_LOG_ERROR("Did not receive confirmation on RTDE output recipe, disconnecting");
287301
disconnect();
@@ -293,17 +307,33 @@ void RTDEClient::setupOutputs(const uint16_t protocol_version)
293307

294308
{
295309
std::vector<std::string> variable_types = splitVariableTypes(tmp_output->variable_types_);
310+
std::vector<std::string> available_variables;
296311
assert(output_recipe_.size() == variable_types.size());
297312
for (std::size_t i = 0; i < variable_types.size(); ++i)
298313
{
299-
URCL_LOG_DEBUG("%s confirmed as datatype: %s", output_recipe_[i].c_str(), variable_types[i].c_str());
314+
const std::string variable_name = output_recipe_[i];
315+
URCL_LOG_DEBUG("%s confirmed as datatype: %s", variable_name.c_str(), variable_types[i].c_str());
316+
300317
if (variable_types[i] == "NOT_FOUND")
301318
{
302-
std::string message = "Variable '" + output_recipe_[i] +
303-
"' not recognized by the robot. Probably your output recipe contains errors";
304-
throw UrException(message);
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
325+
{
326+
available_variables.push_back(variable_name);
305327
}
306328
}
329+
330+
if (available_variables.size() == output_recipe_.size()) {
331+
// All variables are accounted for in the RTDE package
332+
return;
333+
}
334+
335+
// Some variables are not available so retry setting up the communication with a stripped-down output recipe
336+
resetOutputRecipe(available_variables);
307337
return;
308338
}
309339
else
@@ -339,7 +369,7 @@ void RTDEClient::setupInputs()
339369
while (num_retries < MAX_REQUEST_RETRIES)
340370
{
341371
std::unique_ptr<RTDEPackage> package;
342-
if (!pipeline_.getLatestProduct(package, std::chrono::milliseconds(1000)))
372+
if (!pipeline_->getLatestProduct(package, std::chrono::milliseconds(1000)))
343373
{
344374
URCL_LOG_ERROR("Did not receive confirmation on RTDE input recipe, disconnecting");
345375
disconnect();
@@ -395,7 +425,7 @@ void RTDEClient::disconnect()
395425
if (client_state_ > ClientState::UNINITIALIZED)
396426
{
397427
sendPause();
398-
pipeline_.stop();
428+
pipeline_->stop();
399429
stream_.disconnect();
400430
}
401431
client_state_ = ClientState::UNINITIALIZED;
@@ -421,7 +451,7 @@ bool RTDEClient::isRobotBooted()
421451
{
422452
// Set timeout based on target frequency, to make sure that reading doesn't timeout
423453
int timeout = static_cast<int>((1 / target_frequency_) * 1000) * 10;
424-
if (pipeline_.getLatestProduct(package, std::chrono::milliseconds(timeout)))
454+
if (pipeline_->getLatestProduct(package, std::chrono::milliseconds(timeout)))
425455
{
426456
rtde_interface::DataPackage* tmp_input = dynamic_cast<rtde_interface::DataPackage*>(package.get());
427457
tmp_input->getData("timestamp", timestamp);
@@ -451,7 +481,7 @@ bool RTDEClient::start()
451481
return false;
452482
}
453483

454-
pipeline_.run();
484+
pipeline_->run();
455485

456486
if (sendStart())
457487
{
@@ -501,7 +531,7 @@ bool RTDEClient::sendStart()
501531
unsigned int num_retries = 0;
502532
while (num_retries < MAX_REQUEST_RETRIES)
503533
{
504-
if (!pipeline_.getLatestProduct(package, std::chrono::milliseconds(1000)))
534+
if (!pipeline_->getLatestProduct(package, std::chrono::milliseconds(1000)))
505535
{
506536
URCL_LOG_ERROR("Could not get response to RTDE communication start request from robot");
507537
return false;
@@ -543,7 +573,7 @@ bool RTDEClient::sendPause()
543573
int seconds = 5;
544574
while (std::chrono::steady_clock::now() - start < std::chrono::seconds(seconds))
545575
{
546-
if (!pipeline_.getLatestProduct(package, std::chrono::milliseconds(1000)))
576+
if (!pipeline_->getLatestProduct(package, std::chrono::milliseconds(1000)))
547577
{
548578
URCL_LOG_ERROR("Could not get response to RTDE communication pause request from robot");
549579
return false;
@@ -605,7 +635,7 @@ std::vector<std::string> RTDEClient::ensureTimestampIsPresent(const std::vector<
605635
std::unique_ptr<rtde_interface::DataPackage> RTDEClient::getDataPackage(std::chrono::milliseconds timeout)
606636
{
607637
std::unique_ptr<RTDEPackage> urpackage;
608-
if (pipeline_.getLatestProduct(urpackage, timeout))
638+
if (pipeline_->getLatestProduct(urpackage, timeout))
609639
{
610640
rtde_interface::DataPackage* tmp = dynamic_cast<rtde_interface::DataPackage*>(urpackage.get());
611641
if (tmp != nullptr)

0 commit comments

Comments
 (0)