DashboardClient

For CB3 robots and PolyScope 5 the DashboardClient wraps the calls on the Dashboard server directly into C++ functions.

For PolyScope X the so-called Robot API released with PolyScope X 10.11.0 is used. It offers a subset of the Dashboard Server from previous software versions.

After connecting to the dashboard server by using the connect() function, dashboard calls can be done using the command...() functions such as commandCloseSafetyPopup(). These functions are blocking and will wait for the necessary action being done. This can involve querying another call to the dashboard server until the action is done. For example, commandPowerOn() will block until the robot reports “Robotmode: RUNNING” or the given timeout is reached.

The return value of those functions indicate whether or not the call was successful. If you want to get the call’s full response, use the command...WithResponse() calls, instead. They will return a response struct

Listing 3 urcl::DashboardResponse
struct DashboardResponse
{
  bool ok = false;
  std::string message;
  std::unordered_map<std::string, std::variant<std::string, int, bool>> data;
};

The data dictionary of that response struct is populated by each command individually. See the commands’ docstrings for details.

The dashboard_example.cpp shows how to use the dashboard client:

Listing 4 examples/dashboard_example.cpp
 80  auto my_dashboard = std::make_unique<DashboardClient>(robot_ip, policy);
 81  if (!my_dashboard->connect())
 82  {
 83    URCL_LOG_ERROR("Could not connect to dashboard");
 84    return 1;
 85  }
 86
 87  // Bring the robot to a defined state being powered off.
 88  if (version_information->major < 10)
 89  {
 90    if (!my_dashboard->commandPowerOff())
 91    {
 92      URCL_LOG_ERROR("Could not send power off");
 93      return 1;
 94    }
 95    // Get the PolyScope version
 96    std::string version;
 97    my_dashboard->commandPolyscopeVersion(version);
 98    URCL_LOG_INFO(version.c_str());
 99
100    my_dashboard->commandCloseSafetyPopup();
101  }
102  else
103  {
104    // We're ignoring errors here since
105    // powering off an already powered off robot will return an error.
106    my_dashboard->commandPowerOff();
107  }
108
109  // Power it on
110  if (!my_dashboard->commandPowerOn())
111  {
112    URCL_LOG_ERROR("Could not send Power on command");
113    return 1;
114  }
115
116  // Release the brakes
117  if (!my_dashboard->commandBrakeRelease())
118  {
119    URCL_LOG_ERROR("Could not send BrakeRelease command");
120    return 1;
121  }
122
123  // Load existing program
124  std::string program_file_name_to_be_loaded("wait_program.urp");
125  if (version_information->major >= 10)
126  {
127    // For PolyScope X, the program doesn't have an ending
128    program_file_name_to_be_loaded = "wait_program";
129  }
130  if (!my_dashboard->commandLoadProgram(program_file_name_to_be_loaded))
131  {
132    URCL_LOG_ERROR("Could not load %s program", program_file_name_to_be_loaded.c_str());
133    return 1;
134  }
135
136  std::this_thread::sleep_for(std::chrono::seconds(1));
137
138  // Play loaded program
139  if (!my_dashboard->commandPlay())
140  {
141    URCL_LOG_ERROR("Could not play program");
142    return 1;
143  }
144
145  // Pause running program
146  if (!my_dashboard->commandPause())
147  {
148    URCL_LOG_ERROR("Could not pause program");
149    return 1;
150  }
151
152  // Continue
153  if (version_information->major >= 10)
154  {
155    // For PolyScope X, the command is called "resume"
156    if (!my_dashboard->commandResume())
157    {
158      URCL_LOG_ERROR("Could not resume program");
159      return 1;
160    }
161  }
162  else
163  {
164    // For e-Series, the command is called "play"
165    if (!my_dashboard->commandPlay())
166    {
167      URCL_LOG_ERROR("Could not resume program");
168      return 1;
169    }
170  }
171
172  // Stop program
173  if (!my_dashboard->commandStop())
174  {
175    URCL_LOG_ERROR("Could not stop program");
176    return 1;
177  }
178
179  // Power it off
180  if (!my_dashboard->commandPowerOff())
181  {
182    URCL_LOG_ERROR("Could not send Power off command");
183    return 1;
184  }
185
186  if (version_information->major < 10)
187  {
188    // Flush the log
189    if (!my_dashboard->commandSaveLog())
190    {
191      URCL_LOG_ERROR("Could not send the save log command");
192      return 1;
193    }
194
195    // Make a raw request and save the response
196    std::string program_state = my_dashboard->sendAndReceive("programState");
197    URCL_LOG_INFO("Program state: %s", program_state.c_str());
198
199    // The response can be checked with a regular expression
200    bool success = my_dashboard->sendRequest("power off", "Powering off");
201    URCL_LOG_INFO("Power off command success: %d", success);
202  }
203
204  return 0;

CB 3 and PolyScope 5 only

All commands are blocking and will wait for the necessary action being done. The dashboard server’s response will be compared with an expected response. For example, when calling commandPowerOn(timeout), it is checked that the dashboard server is answering "Powering on" and then it is queried until the robot reports "Robotmode: IDLE" or until the timeout is reached. The example contains more commands that follow the same scheme.

If you want to send a query / command to the dashboard server and only want to receive the response, you can use the sendAndReceive() function:

Listing 5 examples/dashboard_example.cpp
195    // Make a raw request and save the response
196    std::string program_state = my_dashboard->sendAndReceive("programState");
197    URCL_LOG_INFO("Program state: %s", program_state.c_str());

For checking the response against an expected regular expression use sendRequest():

Listing 6 examples/dashboard_example.cpp
199    // The response can be checked with a regular expression
200    bool success = my_dashboard->sendRequest("power off", "Powering off");
201    URCL_LOG_INFO("Power off command success: %d", success);

PolyScope X only

Internally, the dashboard client makes calls against a RESTful (Representational State Transfer) API. Hence, all responses contain a JSON-encoded string of the received answer. For example, an answer to a pause request could be

{"state":"PAUSED","message":"Program state changed: PAUSED","details":"Pause successful"}