dashboard_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 // Created on behalf of Universal Robots A/S
6 //
7 // Licensed under the Apache License, Version 2.0 (the "License");
8 // you may not use this file except in compliance with the License.
9 // You may obtain a copy of the License at
10 //
11 // http://www.apache.org/licenses/LICENSE-2.0
12 //
13 // Unless required by applicable law or agreed to in writing, software
14 // distributed under the License is distributed on an "AS IS" BASIS,
15 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 // See the License for the specific language governing permissions and
17 // limitations under the License.
18 // -- END LICENSE BLOCK ------------------------------------------------
19 
20 //----------------------------------------------------------------------
27 //----------------------------------------------------------------------
28 
29 #include <iostream>
30 #include <regex>
31 #include <thread>
32 #include <unistd.h>
33 #include <ur_client_library/log.h>
36 
37 using namespace std::chrono_literals;
38 
39 namespace urcl
40 {
41 DashboardClient::DashboardClient(const std::string& host) : host_(host), port_(DASHBOARD_SERVER_PORT)
42 {
43 }
44 
45 void DashboardClient::rtrim(std::string& str, const std::string& chars)
46 {
47  str.erase(str.find_last_not_of(chars) + 1);
48 }
49 
51 {
53  {
54  URCL_LOG_ERROR("%s", "Socket is already connected. Refusing to reconnect.");
55  return false;
56  }
57  bool ret_val = false;
58 
59  timeval tv;
60 
61  while (not ret_val)
62  {
63  // The first read after connection can take more time.
64  tv.tv_sec = 10;
65  tv.tv_usec = 0;
66  TCPSocket::setReceiveTimeout(tv);
67  try
68  {
69  if (TCPSocket::setup(host_, port_))
70  {
71  URCL_LOG_INFO("%s", read().c_str());
72  ret_val = true;
73  }
74  }
75  catch (const TimeoutException&)
76  {
77  URCL_LOG_WARN("Did not receive dashboard bootup message although connection was established. This should not "
78  "happen, please contact the package maintainers. Retrying anyway...");
79  }
80  }
81 
82  // Reset read timeout to "normal" socket timeout
83  tv.tv_sec = 1;
84  tv.tv_usec = 0;
85  TCPSocket::setReceiveTimeout(tv);
86 
87  std::string pv;
89 
90  return ret_val;
91 }
92 
94 {
95  URCL_LOG_INFO("Disconnecting from Dashboard server on %s:%d", host_.c_str(), port_);
96  TCPSocket::close();
97 }
98 
99 bool DashboardClient::send(const std::string& text)
100 {
101  size_t len = text.size();
102  const uint8_t* data = reinterpret_cast<const uint8_t*>(text.c_str());
103  size_t written;
104  return TCPSocket::write(data, len, written);
105 }
106 
108 {
109  std::stringstream result;
110  char character;
111  size_t read_chars = 99;
112  while (read_chars > 0)
113  {
114  if (!TCPSocket::read((uint8_t*)&character, 1, read_chars))
115  {
116  disconnect();
117  throw TimeoutException("Did not receive answer from dashboard server in time. Disconnecting from dashboard "
118  "server.",
119  *recv_timeout_);
120  }
121  result << character;
122  if (character == '\n')
123  {
124  break;
125  }
126  }
127  return result.str();
128 }
129 
130 std::string DashboardClient::sendAndReceive(const std::string& text)
131 {
132  std::string command = text;
133  if (text.back() != '\n')
134  {
135  command = text + "\n";
136  }
137  std::string response = "ERROR";
138  std::lock_guard<std::mutex> lock(write_mutex_);
139  if (send(command))
140  {
141  response = read();
142  }
143  else
144  {
145  throw UrException("Failed to send request to dashboard server. Are you connected to the Dashboard Server?");
146  }
147  rtrim(response);
148 
149  return response;
150 }
151 
152 bool DashboardClient::sendRequest(const std::string& command, const std::string& expected)
153 {
154  URCL_LOG_DEBUG("Send Request: %s", command.c_str());
155  std::string response = sendAndReceive(command);
156  bool ret = std::regex_match(response, std::regex(expected));
157  if (!ret)
158  {
159  throw UrException("Expected: " + expected + ", but received: " + response);
160  }
161  return ret;
162 }
163 
164 std::string DashboardClient::sendRequestString(const std::string& command, const std::string& expected)
165 {
166  URCL_LOG_DEBUG("Send Request: %s", command.c_str());
167  std::string response = sendAndReceive(command);
168  bool ret = std::regex_match(response, std::regex(expected));
169  if (!ret)
170  {
171  throw UrException("Expected: " + expected + ", but received: " + response);
172  }
173  return response;
174 }
175 
176 bool DashboardClient::waitForReply(const std::string& command, const std::string& expected,
177  const std::chrono::duration<double> timeout)
178 {
179  const std::chrono::duration<double> wait_period = 100ms;
180 
181  std::chrono::duration<double> time_done(0);
182  std::string response;
183 
184  while (time_done < timeout)
185  {
186  // Send the request
187  response = sendAndReceive(command);
188 
189  // Check if the response was as expected
190  if (std::regex_match(response, std::regex(expected)))
191  {
192  return true;
193  }
194 
195  // wait 100ms before trying again
196  std::this_thread::sleep_for(wait_period);
197  time_done += wait_period;
198  }
199 
200  URCL_LOG_WARN("Did not got the expected \"%s\" response within the timeout. Last response was: \"%s\"",
201  expected.c_str(), response.c_str()); // Is a warning here so retryCommand does not throw when retrying
202  return false;
203 }
204 
205 bool DashboardClient::retryCommand(const std::string& requestCommand, const std::string& requestExpectedResponse,
206  const std::string& waitRequest, const std::string& waitExpectedResponse,
207  const std::chrono::duration<double> timeout,
208  const std::chrono::duration<double> retry_period)
209 {
210  std::chrono::duration<double> time_done(0);
211  do
212  {
213  sendRequest(requestCommand, requestExpectedResponse);
214  time_done += retry_period;
215 
216  if (waitForReply(waitRequest, waitExpectedResponse, retry_period))
217  {
218  return true;
219  }
220  } while (time_done < timeout);
221  return false;
222 }
223 
225 {
226  assertVersion("5.0.0", "3.0", "power off");
227  return sendRequest("power off", "Powering off") && waitForReply("robotmode", "Robotmode: POWER_OFF");
228 }
229 
230 bool DashboardClient::commandPowerOn(const std::chrono::duration<double> timeout)
231 {
232  assertVersion("5.0.0", "3.0", "power on");
233  return retryCommand("power on", "Powering on", "robotmode", "Robotmode: IDLE", timeout);
234 }
235 
237 {
238  assertVersion("5.0.0", "3.0", "brake release");
239  return sendRequest("brake release", "Brake releasing") && waitForReply("robotmode", "Robotmode: RUNNING");
240 }
241 
242 bool DashboardClient::commandLoadProgram(const std::string& program_file_name)
243 {
244  assertVersion("5.0.0", "1.4", "load <program>");
245  return sendRequest("load " + program_file_name + "", "(?:Loading program: ).*(?:" + program_file_name + ").*") &&
246  waitForReply("programState", "STOPPED " + program_file_name);
247 }
248 
249 bool DashboardClient::commandLoadInstallation(const std::string& installation_file_name)
250 {
251  assertVersion("5.0.0", "3.2", "load installation");
252  return sendRequest("load installation " + installation_file_name,
253  "(?:Loading installation: ).*(?:" + installation_file_name + ").*");
254 }
255 
257 {
258  assertVersion("5.0.0", "1.4", "play");
259  return sendRequest("play", "Starting program") && waitForReply("programState", "(?:PLAYING ).*");
260 }
261 
263 {
264  assertVersion("5.0.0", "1.4", "pause");
265  return sendRequest("pause", "Pausing program") && waitForReply("programState", "(?:PAUSED ).*");
266 }
267 
269 {
270  assertVersion("5.0.0", "1.4", "stop");
271  return sendRequest("stop", "Stopped") && waitForReply("programState", "(?:STOPPED ).*");
272 }
273 
275 {
276  assertVersion("5.0.0", "1.6", "close popup");
277  return sendRequest("close popup", "closing popup");
278 }
279 
281 {
282  assertVersion("5.0.0", "3.1", "close safety popup");
283  return sendRequest("close safety popup", "closing safety popup");
284 }
285 
287 {
288  assertVersion("5.1.0", "3.7", "restart safety");
289  return sendRequest("restart safety", "Restarting safety") && waitForReply("robotmode", "Robotmode: POWER_OFF");
290 }
291 
293 {
294  assertVersion("5.0.0", "3.1", "unlock protective stop");
295  return sendRequest("unlock protective stop", "Protective stop releasing");
296 }
297 
299 {
300  assertVersion("5.0.0", "1.4", "shutdown");
301  return sendRequest("shutdown", "Shutting down");
302 }
303 
305 {
306  assertVersion("5.0.0", "1.4", "quit");
307  return sendRequest("quit", "Disconnected");
308 }
309 
311 {
312  assertVersion("5.0.0", "1.6", "running");
313  return sendRequest("running", "Program running: true");
314 }
315 
317 {
318  assertVersion("5.0.0", "1.8", "isProgramSaved");
319  return sendRequest("isProgramSaved", "(?:true ).*");
320 }
321 
323 {
324  assertVersion("5.6.0", "-", "is in remote control");
325  std::string response = sendAndReceive("is in remote control");
326  bool ret = std::regex_match(response, std::regex("true"));
327  return ret;
328 }
329 
330 bool DashboardClient::commandPopup(const std::string& popup_text)
331 {
332  assertVersion("5.0.0", "1.6", "popup");
333  return sendRequest("popup " + popup_text, "showing popup");
334 }
335 
336 bool DashboardClient::commandAddToLog(const std::string& log_text)
337 {
338  assertVersion("5.0.0", "1.8", "addToLog");
339  return sendRequest("addToLog " + log_text, "Added log message");
340 }
341 
342 bool DashboardClient::commandPolyscopeVersion(std::string& polyscope_version)
343 {
344  std::string expected = "(?:URSoftware ).*";
345  polyscope_version = sendRequestString("PolyscopeVersion", expected);
346  std::string version_string = polyscope_version.substr(polyscope_version.find(" ") + 1,
347  polyscope_version.find(" (") - polyscope_version.find(" ") - 1);
349  return std::regex_match(polyscope_version, std::regex(expected));
350 }
351 
352 bool DashboardClient::commandGetRobotModel(std::string& robot_model)
353 {
354  assertVersion("5.6.0", "3.12", "get robot model");
355  std::string expected = "(?:UR).*";
356  robot_model = sendRequestString("get robot model", expected);
357  return std::regex_match(robot_model, std::regex(expected));
358 }
359 
360 bool DashboardClient::commandGetSerialNumber(std::string& serial_number)
361 {
362  assertVersion("5.6.0", "3.12", "get serial number");
363  std::string expected = "(?:20).*";
364  serial_number = sendRequestString("get serial number", expected);
365  return std::regex_match(serial_number, std::regex(expected));
366 }
367 
368 bool DashboardClient::commandRobotMode(std::string& robot_mode)
369 {
370  assertVersion("5.0.0", "1.6", "robotmode");
371  std::string expected = "(?:Robotmode: ).*";
372  robot_mode = sendRequestString("robotmode", expected);
373  return std::regex_match(robot_mode, std::regex(expected));
374 }
375 
376 bool DashboardClient::commandGetLoadedProgram(std::string& loaded_program)
377 {
378  assertVersion("5.0.0", "1.6", "get loaded program");
379  std::string expected = "(?:Loaded program: ).*";
380  loaded_program = sendRequestString("get loaded program", expected);
381  return std::regex_match(loaded_program, std::regex(expected));
382 }
383 
384 bool DashboardClient::commandSafetyMode(std::string& safety_mode)
385 {
386  assertVersion("5.0.0", "3.0", "safetymode");
387  std::string expected = "(?:Safetymode: ).*";
388  safety_mode = sendRequestString("safetymode", expected);
389  return std::regex_match(safety_mode, std::regex(expected));
390 }
391 
392 bool DashboardClient::commandSafetyStatus(std::string& safety_status)
393 {
394  assertVersion("5.4.0", "3.11", "safetystatus");
395  std::string expected = "(?:Safetystatus: ).*";
396  safety_status = sendRequestString("safetystatus", expected);
397  return std::regex_match(safety_status, std::regex(expected));
398 }
399 
400 bool DashboardClient::commandProgramState(std::string& program_state)
401 {
402  assertVersion("5.0.0", "1.8", "programState");
403  std::string expected = "(?:).*";
404  program_state = sendRequestString("programState", expected);
405  return !std::regex_match(program_state, std::regex("(?:could not understand).*"));
406 }
407 
408 bool DashboardClient::commandGetOperationalMode(std::string& operational_mode)
409 {
410  assertVersion("5.6.0", "-", "get operational mode");
411  std::string expected = "(?:).*";
412  operational_mode = sendRequestString("get operational mode", expected);
413  return !std::regex_match(operational_mode, std::regex("(?:could not understand).*"));
414 }
415 
416 bool DashboardClient::commandSetOperationalMode(const std::string& operational_mode)
417 {
418  assertVersion("5.0.0", "-", "set operational mode");
419  return sendRequest("set operational mode " + operational_mode,
420  "(?:Operational mode ).*(?:" + operational_mode + ").*");
421 }
422 
424 {
425  assertVersion("5.0.0", "-", "clear operational mode");
426  return sendRequest("clear operational mode", "(?:No longer controlling the operational mode. ).*");
427 }
428 
429 bool DashboardClient::commandSetUserRole(const std::string& user_role)
430 {
431  assertVersion("-", "1.8", "setUserRole");
432  return sendRequest("setUserRole " + user_role, "(?:Setting user role: ).*");
433 }
434 
435 bool DashboardClient::commandGetUserRole(std::string& user_role)
436 {
437  assertVersion("-", "1.8", "getUserRole");
438  std::string expected = "(?:).*";
439  user_role = sendRequestString("getUserRole", expected);
440  return !std::regex_match(user_role, std::regex("(?:could not understand).*"));
441 }
442 
443 bool DashboardClient::commandGenerateFlightReport(const std::string& report_type)
444 {
445  assertVersion("5.8.0", "3.13", "generate flight report");
446  timeval tv;
447  tv.tv_sec = 180;
448  tv.tv_usec = 0;
449  TCPSocket::setReceiveTimeout(tv); // Set timeout to 3 minutes as this command can take a long time to complete
450  bool ret = sendRequest("generate flight report " + report_type, "(?:Flight Report generated with id:).*");
451  tv.tv_sec = 1; // Reset timeout to standard timeout
452  TCPSocket::setReceiveTimeout(tv);
453  return ret;
454 }
455 
456 bool DashboardClient::commandGenerateSupportFile(const std::string& dir_path)
457 {
458  assertVersion("5.8.0", "3.13", "generate support file");
459  timeval tv;
460  tv.tv_sec = 600;
461  tv.tv_usec = 0;
462  TCPSocket::setReceiveTimeout(tv); // Set timeout to 10 minutes as this command can take a long time to complete
463  bool ret = sendRequest("generate support file " + dir_path, "(?:Completed successfully:).*");
464  tv.tv_sec = 1; // Reset timeout to standard timeout
465  TCPSocket::setReceiveTimeout(tv);
466  return ret;
467 }
468 
470 {
471  assertVersion("5.0.0", "1.8", "save log");
472  return sendRequest("saveLog", "Log saved to disk");
473 }
474 
475 void DashboardClient::assertVersion(const std::string& e_series_min_ver, const std::string& cb3_min_ver,
476  const std::string& required_call)
477 {
478  if (!polyscope_version_.isESeries() && cb3_min_ver == "-")
479  {
480  std::stringstream ss;
481  ss << "The dasboard call '" << required_call
482  << "' is only available on e-series robots, but you seem to be running version " << polyscope_version_;
483  throw UrException(ss.str());
484  }
485 
486  if (polyscope_version_.isESeries() && e_series_min_ver == "-")
487  {
488  std::stringstream ss;
489  ss << "The dasboard call '" << required_call
490  << "' is only available on pre-e-series robots (5.x.y), but you seem to be running version "
492  throw UrException(ss.str());
493  }
494 
495  auto ref = polyscope_version_.isESeries() ? VersionInformation::fromString(e_series_min_ver) :
496  VersionInformation::fromString(cb3_min_ver);
497  if (ref > polyscope_version_)
498  {
499  std::stringstream ss;
500  ss << "Polyscope version " << polyscope_version_ << " isn't recent enough to use dashboard call '" << required_call
501  << "'";
502  throw UrException(ss.str());
503  }
504 }
505 
506 } // namespace urcl
void assertVersion(const std::string &e_series_min_ver, const std::string &cb3_min_ver, const std::string &required_call)
Makes sure that the dashboard_server&#39;s version is above the required version.
bool commandGetSerialNumber(std::string &serial_number)
Get Serial number.
std::string sendRequestString(const std::string &command, const std::string &expected)
Sends command and compare it with the expected answer.
bool commandSafetyMode(std::string &safety_mode)
Get Safety mode.
#define URCL_LOG_ERROR(...)
Definition: log.h:26
bool commandSetUserRole(const std::string &user_role)
Send Set user role command (Only available for CB3)
VersionInformation polyscope_version_
bool waitForReply(const std::string &command, const std::string &expected, std::chrono::duration< double > timeout=std::chrono::seconds(30))
brief Sends a command and wait until it returns the expected answer
bool commandIsProgramSaved()
Send "Is program saved" request command.
bool retryCommand(const std::string &requestCommand, const std::string &requestExpectedResponse, const std::string &waitRequest, const std::string &waitExpectedResponse, const std::chrono::duration< double > timeout, const std::chrono::duration< double > retry_period=std::chrono::seconds(1))
Keep Sending the requesting Command and wait until it returns the expected answer.
bool commandGetRobotModel(std::string &robot_model)
Get Robot model.
bool send(const std::string &text)
std::unique_ptr< timeval > recv_timeout_
Definition: tcp_socket.h:64
bool commandUnlockProtectiveStop()
Send Unlock Protective stop popup command.
bool commandClosePopup()
Send Close popup command.
bool commandStop()
Send Stop program command.
bool commandGenerateSupportFile(const std::string &dir_path)
Send Generate support file command.
bool commandBrakeRelease()
Send Brake release command.
std::string sendAndReceive(const std::string &command)
Sends a command through the socket and waits for an answer.
bool commandPopup(const std::string &popup_text)
Send popup command.
bool commandQuit()
Send Quit command.
void rtrim(std::string &str, const std::string &chars="\\\")
bool commandClearOperationalMode()
Send Clear operational mode command.
bool sendRequest(const std::string &command, const std::string &expected)
Sends command and compare it with the expected answer.
bool commandShutdown()
Send Shutdown command.
bool commandLoadProgram(const std::string &program_file_name)
Send Load program command.
bool commandProgramState(std::string &program_state)
Get Program state.
SocketState getState()
Getter for the state of the socket.
Definition: tcp_socket.h:78
#define URCL_LOG_DEBUG(...)
Definition: log.h:23
bool commandSafetyStatus(std::string &safety_status)
Get Safety status.
bool commandAddToLog(const std::string &log_text)
Send text to log.
bool connect()
Opens a connection to the dashboard server on the host as specified in the constructor.
bool commandSaveLog()
Flush the polyscope log to the log_history.txt file.
bool commandLoadInstallation(const std::string &installation_file_name)
Send Load installation command.
#define URCL_LOG_WARN(...)
Definition: log.h:24
bool commandPowerOn(const std::chrono::duration< double > timeout=std::chrono::seconds(300))
Send Power on command.
bool commandPowerOff()
Send Power off command.
bool commandRunning()
Send Running command.
bool commandRobotMode(std::string &robot_mode)
Get Robot mode.
A specialized exception representing that communication to the tool is not possible.
Definition: exceptions.h:109
bool commandGetLoadedProgram(std::string &loaded_program)
Get Loaded Program.
Socket is connected and ready to use.
void disconnect()
Makes sure no connection to the dashboard server is held inside the object.
bool commandIsInRemoteControl()
Send "Is in remote control" query command.
bool commandPause()
Send Pause program command.
bool commandRestartSafety()
Send Restart Safety command.
bool commandPlay()
Send Play program command.
bool commandGenerateFlightReport(const std::string &report_type)
Send Generate flight report command.
bool commandSetOperationalMode(const std::string &operational_mode)
Send Set operational mode command (Only available for e-series)
bool commandGetUserRole(std::string &user_role)
Send Get user role command (Only available for CB3)
bool commandGetOperationalMode(std::string &operational_mode)
Get Operational mode.
#define URCL_LOG_INFO(...)
Definition: log.h:25
bool commandCloseSafetyPopup()
Send Close safety popup command.
Our base class for exceptions. Specialized exceptions should inherit from those.
Definition: exceptions.h:41
bool commandPolyscopeVersion(std::string &polyscope_version)
Get Polyscope version.
static VersionInformation fromString(const std::string &str)
Parses a version string into a VersionInformation object.


ur_client_library
Author(s): Thomas Timm Andersen, Simon Rasmussen, Felix Exner, Lea Steffen, Tristan Schnell
autogenerated on Tue Jul 4 2023 02:09:47