src/rtde/rtde_client.cpp
Go to the documentation of this file.
1 // this is for emacs file handling -*- mode: c++; indent-tabs-mode: nil -*-
2 
3 // -- BEGIN LICENSE BLOCK ----------------------------------------------
4 // Copyright 2019 FZI Forschungszentrum Informatik
5 //
6 // Licensed under the Apache License, Version 2.0 (the "License");
7 // you may not use this file except in compliance with the License.
8 // You may obtain a copy of the License at
9 //
10 // http://www.apache.org/licenses/LICENSE-2.0
11 //
12 // Unless required by applicable law or agreed to in writing, software
13 // distributed under the License is distributed on an "AS IS" BASIS,
14 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 // See the License for the specific language governing permissions and
16 // limitations under the License.
17 // -- END LICENSE BLOCK ------------------------------------------------
18 
19 //----------------------------------------------------------------------
26 //----------------------------------------------------------------------
27 
30 
31 namespace urcl
32 {
33 namespace rtde_interface
34 {
35 RTDEClient::RTDEClient(std::string robot_ip, comm::INotifier& notifier, const std::string& output_recipe_file,
36  const std::string& input_recipe_file)
37  : stream_(robot_ip, UR_RTDE_PORT)
38  , output_recipe_(readRecipe(output_recipe_file))
39  , input_recipe_(readRecipe(input_recipe_file))
40  , parser_(output_recipe_)
41  , prod_(stream_, parser_)
42  , pipeline_(prod_, PIPELINE_NAME, notifier)
43  , writer_(&stream_, input_recipe_)
44  , max_frequency_(URE_MAX_FREQUENCY)
45 {
46 }
47 
49 {
50  pipeline_.stop();
51 }
52 
54 {
55  // A running pipeline is needed inside setup
56  pipeline_.init();
57  pipeline_.run();
58 
59  uint16_t protocol_version = MAX_RTDE_PROTOCOL_VERSION;
60  while (!negotiateProtocolVersion(protocol_version))
61  {
62  URCL_LOG_INFO("Robot did not accept RTDE protocol version '%hu'. Trying lower protocol version", protocol_version);
63  protocol_version--;
64  if (protocol_version == 0)
65  {
66  throw UrException("Protocol version for RTDE communication could not be established. Robot didn't accept any of "
67  "the suggested versions.");
68  }
69  }
70  URCL_LOG_INFO("Negotiated RTDE protocol version to %hu.", protocol_version);
71  parser_.setProtocolVersion(protocol_version);
72 
74  if (urcontrol_version_.major < 5)
75  {
77  }
78 
79  setupOutputs(protocol_version);
80  setupInputs();
81 
82  // We finished communication for now
83  pipeline_.stop();
84 
85  // We throw exceptions on the way, so if we made it that far, we can return true.
86  return true;
87 }
88 
89 bool RTDEClient::negotiateProtocolVersion(const uint16_t protocol_version)
90 {
91  static unsigned num_retries = 0;
92  uint8_t buffer[4096];
93  size_t size;
94  size_t written;
95  size = RequestProtocolVersionRequest::generateSerializedRequest(buffer, protocol_version);
96  if (!stream_.write(buffer, size, written))
97  throw UrException("Sending protocol version query to robot failed.");
98 
99  std::unique_ptr<RTDEPackage> package;
100  while (num_retries < MAX_REQUEST_RETRIES)
101  {
102  if (!pipeline_.getLatestProduct(package, std::chrono::milliseconds(1000)))
103  {
104  throw UrException("No answer to RTDE protocol version negotiation request was received from robot. This should "
105  "not "
106  "happen!");
107  }
108 
109  if (rtde_interface::RequestProtocolVersion* tmp_version =
110  dynamic_cast<rtde_interface::RequestProtocolVersion*>(package.get()))
111  {
112  // Reset the num_tries variable in case we have to try with another protocol version.
113  num_retries = 0;
114  return tmp_version->accepted_;
115  }
116  else
117  {
118  std::stringstream ss;
119  ss << "Did not receive protocol negotiation answer from robot. Message received instead: " << std::endl
120  << package->toString() << ". Retrying...";
121  num_retries++;
122  URCL_LOG_WARN("%s", ss.str().c_str());
123  }
124  }
125  std::stringstream ss;
126  ss << "Could not negotiate RTDE protocol version after " << MAX_REQUEST_RETRIES
127  << " tries. Please check the output of the "
128  "negotiation attempts above to get a hint what could be wrong.";
129  throw UrException(ss.str());
130 }
131 
133 {
134  static unsigned num_retries = 0;
135  uint8_t buffer[4096];
136  size_t size;
137  size_t written;
139  if (!stream_.write(buffer, size, written))
140  throw UrException("Sending urcontrol version query request to robot failed.");
141 
142  std::unique_ptr<RTDEPackage> package;
143  while (num_retries < MAX_REQUEST_RETRIES)
144  {
145  if (!pipeline_.getLatestProduct(package, std::chrono::milliseconds(1000)))
146  throw UrException("No answer to urcontrol version query was received from robot. This should not happen!");
147 
148  if (rtde_interface::GetUrcontrolVersion* tmp_urcontrol_version =
149  dynamic_cast<rtde_interface::GetUrcontrolVersion*>(package.get()))
150  {
151  urcontrol_version_ = tmp_urcontrol_version->version_information_;
152  return;
153  }
154  else
155  {
156  std::stringstream ss;
157  ss << "Did not receive protocol negotiation answer from robot. Message received instead: " << std::endl
158  << package->toString() << ". Retrying...";
159  num_retries++;
160  URCL_LOG_WARN("%s", ss.str().c_str());
161  }
162  }
163  std::stringstream ss;
164  ss << "Could not query urcontrol version after " << MAX_REQUEST_RETRIES
165  << " tries. Please check the output of the "
166  "negotiation attempts above to get a hint what could be wrong.";
167  throw UrException(ss.str());
168 }
169 
170 void RTDEClient::setupOutputs(const uint16_t protocol_version)
171 {
172  static unsigned num_retries = 0;
173  size_t size;
174  size_t written;
175  uint8_t buffer[4096];
176  URCL_LOG_INFO("Setting up RTDE communication with frequency %f", max_frequency_);
177  if (protocol_version == 2)
178  {
180  }
181  else
182  {
184  }
185 
186  // Send output recipe to robot
187  if (!stream_.write(buffer, size, written))
188  throw UrException("Could not send RTDE output recipe to robot.");
189 
190  std::unique_ptr<RTDEPackage> package;
191  while (num_retries < MAX_REQUEST_RETRIES)
192  {
193  if (!pipeline_.getLatestProduct(package, std::chrono::milliseconds(1000)))
194  {
195  throw UrException("Did not receive confirmation on RTDE output recipe.");
196  }
197 
199  dynamic_cast<rtde_interface::ControlPackageSetupOutputs*>(package.get()))
200 
201  {
202  std::vector<std::string> variable_types = splitVariableTypes(tmp_output->variable_types_);
203  assert(output_recipe_.size() == variable_types.size());
204  for (std::size_t i = 0; i < variable_types.size(); ++i)
205  {
206  URCL_LOG_DEBUG("%s confirmed as datatype: %s", output_recipe_[i].c_str(), variable_types[i].c_str());
207  if (variable_types[i] == "NOT_FOUND")
208  {
209  std::string message = "Variable '" + output_recipe_[i] +
210  "' not recognized by the robot. Probably your output recipe contains errors";
211  throw UrException(message);
212  }
213  }
214  return;
215  }
216  else
217  {
218  std::stringstream ss;
219  ss << "Did not receive answer to RTDE output setup. Message received instead: " << std::endl
220  << package->toString() << ". Retrying...";
221  num_retries++;
222  URCL_LOG_WARN("%s", ss.str().c_str());
223  }
224  }
225  std::stringstream ss;
226  ss << "Could not setup RTDE outputs after " << MAX_REQUEST_RETRIES
227  << " tries. Please check the output of the "
228  "negotiation attempts above to get a hint what could be wrong.";
229  throw UrException(ss.str());
230 }
231 
233 {
234  static unsigned num_retries = 0;
235  size_t size;
236  size_t written;
237  uint8_t buffer[4096];
239  if (!stream_.write(buffer, size, written))
240  throw UrException("Could not send RTDE input recipe to robot.");
241 
242  std::unique_ptr<RTDEPackage> package;
243  while (num_retries < MAX_REQUEST_RETRIES)
244  {
245  if (!pipeline_.getLatestProduct(package, std::chrono::milliseconds(1000)))
246  throw UrException("Did not receive confirmation on RTDE input recipe.");
247 
249  dynamic_cast<rtde_interface::ControlPackageSetupInputs*>(package.get()))
250 
251  {
252  std::vector<std::string> variable_types = splitVariableTypes(tmp_input->variable_types_);
253  assert(input_recipe_.size() == variable_types.size());
254  for (std::size_t i = 0; i < variable_types.size(); ++i)
255  {
256  URCL_LOG_DEBUG("%s confirmed as datatype: %s", input_recipe_[i].c_str(), variable_types[i].c_str());
257  if (variable_types[i] == "NOT_FOUND")
258  {
259  std::string message = "Variable '" + input_recipe_[i] +
260  "' not recognized by the robot. Probably your input recipe contains errors";
261  throw UrException(message);
262  }
263  else if (variable_types[i] == "IN_USE")
264  {
265  std::string message = "Variable '" + input_recipe_[i] +
266  "' is currently controlled by another RTDE client. The input recipe can't be used as "
267  "configured";
268  throw UrException(message);
269  }
270  }
271 
272  writer_.init(tmp_input->input_recipe_id_);
273 
274  return;
275  }
276  else
277  {
278  std::stringstream ss;
279  ss << "Did not receive answer to RTDE input setup. Message received instead: " << std::endl
280  << package->toString() << ". Retrying...";
281  num_retries++;
282  URCL_LOG_WARN("%s", ss.str().c_str());
283  }
284  }
285  std::stringstream ss;
286  ss << "Could not setup RTDE inputs after " << MAX_REQUEST_RETRIES
287  << " tries. Please check the output of the "
288  "negotiation attempts above to get a hint what could be wrong.";
289  throw UrException(ss.str());
290 }
291 
293 {
294  static unsigned num_retries = 0;
295  uint8_t buffer[4096];
296  size_t size;
297  size_t written;
298  pipeline_.run();
300  std::unique_ptr<RTDEPackage> package;
301  if (!stream_.write(buffer, size, written))
302  throw UrException("Sending RTDE start command failed!");
303  while (num_retries < MAX_REQUEST_RETRIES)
304  {
305  if (!pipeline_.getLatestProduct(package, std::chrono::milliseconds(1000)))
306  throw UrException("Could not get response to RTDE communication start request from robot. This should not "
307  "happen!");
308  if (rtde_interface::ControlPackageStart* tmp = dynamic_cast<rtde_interface::ControlPackageStart*>(package.get()))
309  {
310  return tmp->accepted_;
311  }
312  else
313  {
314  std::stringstream ss;
315  ss << "Did not receive answer to RTDE start request. Message received instead: " << std::endl
316  << package->toString() << ". Retrying...";
317  URCL_LOG_WARN("%s", ss.str().c_str());
318  }
319  }
320  std::stringstream ss;
321  ss << "Could not start RTDE communication after " << MAX_REQUEST_RETRIES
322  << " tries. Please check the output of the "
323  "negotiation attempts above to get a hint what could be wrong.";
324  throw UrException(ss.str());
325 }
326 
327 std::vector<std::string> RTDEClient::readRecipe(const std::string& recipe_file)
328 {
329  std::vector<std::string> recipe;
330  std::ifstream file(recipe_file);
331  if (file.fail())
332  {
333  std::stringstream msg;
334  msg << "Opening file '" << recipe_file << "' failed with error: " << strerror(errno);
335  URCL_LOG_ERROR("%s", msg.str().c_str());
336  throw UrException(msg.str());
337  }
338  std::string line;
339  while (std::getline(file, line))
340  {
341  recipe.push_back(line);
342  }
343  return recipe;
344 }
345 
346 std::unique_ptr<rtde_interface::DataPackage> RTDEClient::getDataPackage(std::chrono::milliseconds timeout)
347 {
348  std::unique_ptr<RTDEPackage> urpackage;
349  if (pipeline_.getLatestProduct(urpackage, timeout))
350  {
351  rtde_interface::DataPackage* tmp = dynamic_cast<rtde_interface::DataPackage*>(urpackage.get());
352  if (tmp != nullptr)
353  {
354  urpackage.release();
355  return std::unique_ptr<rtde_interface::DataPackage>(tmp);
356  }
357  }
358  return std::unique_ptr<rtde_interface::DataPackage>(nullptr);
359 }
360 
361 std::string RTDEClient::getIP() const
362 {
363  return stream_.getIP();
364 }
365 
367 {
368  return writer_;
369 }
370 
371 std::vector<std::string> RTDEClient::splitVariableTypes(const std::string& variable_types) const
372 {
373  std::vector<std::string> result;
374  std::stringstream ss(variable_types);
375  std::string substr = "";
376  while (getline(ss, substr, ','))
377  {
378  result.push_back(substr);
379  }
380  return result;
381 }
382 } // namespace rtde_interface
383 } // namespace urcl
static const unsigned MAX_REQUEST_RETRIES
Definition: rtde_client.h:52
void setProtocolVersion(uint16_t protocol_version)
Definition: rtde_parser.h:119
static size_t generateSerializedRequest(uint8_t *buffer, double output_frequency, std::vector< std::string > variable_names)
Generates a serialized package.
void init(uint8_t recipe_id)
Starts the writer thread, which periodically clears the queue to write packages to the robot...
Definition: rtde_writer.cpp:39
#define URCL_LOG_ERROR(...)
Definition: log.h:37
This class handles the robot&#39;s response to a requested start in RTDE data package communication...
RTDEWriter & getWriter()
Getter for the RTDE writer, which is used to send data via the RTDE interface to the robot...
std::vector< std::string > output_recipe_
Definition: rtde_client.h:166
static constexpr const double CB3_MAX_FREQUENCY
Definition: rtde_client.h:177
std::vector< std::string > readRecipe(const std::string &recipe_file)
static size_t generateSerializedRequest(uint8_t *buffer, std::vector< std::string > variable_names)
Generates a serialized package.
bool start()
Triggers the robot to start sending RTDE data packages in the negotiated format.
std::vector< std::string > splitVariableTypes(const std::string &variable_types) const
Splits a variable_types string as reported from the robot into single variable type strings...
static size_t generateSerializedRequest(uint8_t *buffer, uint16_t version)
Generates a serialized package.
std::vector< std::string > input_recipe_
Definition: rtde_client.h:167
static const std::string PIPELINE_NAME
Definition: rtde_client.h:45
The RTDEWriter class offers an abstraction layer to send data to the robot via the RTDE interface...
Definition: rtde_writer.h:48
std::unique_ptr< rtde_interface::DataPackage > getDataPackage(std::chrono::milliseconds timeout)
Reads the pipeline to fetch the next data package.
This class handles the package detailing the UR control version sent by the robot.
comm::Pipeline< RTDEPackage > pipeline_
Definition: rtde_client.h:170
Parent class for notifiers.
Definition: pipeline.h:209
static size_t generateSerializedRequest(uint8_t *buffer)
Generates a serialized package.
uint32_t major
Major version number.
#define URCL_LOG_DEBUG(...)
Definition: log.h:34
This class handles the robot&#39;s response to a requested output recipe setup.
static size_t generateSerializedRequest(uint8_t *buffer)
Generates a serialized package.
This class handles the robot&#39;s response after trying to set the used RTDE protocol version...
comm::URStream< RTDEPackage > stream_
Definition: rtde_client.h:165
#define URCL_LOG_WARN(...)
Definition: log.h:35
This class handles the robot&#39;s response to a requested input recipe setup.
bool negotiateProtocolVersion(const uint16_t protocol_version)
std::string getIP() const
Returns the IP address (of the machine running this driver) used for the socket connection.
The DataPackage class handles communication in the form of RTDE data packages both to and from the ro...
Definition: data_package.h:59
bool init()
Sets up RTDE communication with the robot. The handshake includes negotiation of the used protocol ve...
static const uint16_t MAX_RTDE_PROTOCOL_VERSION
Definition: rtde_client.h:51
#define URCL_LOG_INFO(...)
Definition: log.h:36
Our base class for exceptions. Specialized exceptions should inherit from those.
Definition: exceptions.h:40
VersionInformation urcontrol_version_
Definition: rtde_client.h:173
void setupOutputs(const uint16_t protocol_version)
static const int UR_RTDE_PORT
Definition: rtde_client.h:44


ur_client_library
Author(s): Thomas Timm Andersen, Simon Rasmussen, Felix Exner, Lea Steffen, Tristan Schnell
autogenerated on Sun May 9 2021 02:16:26