Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
ff1ef39
Implement assertHasCommand for DashboardClientImplX
urfeex May 15, 2026
153218e
Add popup and closePopup for DashboardClientImplX
urfeex May 15, 2026
d68d1b1
Create table for polyscope X compatibility
URJala May 18, 2026
97ec526
Implement commandPolyscopeVersion
URJala May 18, 2026
25716e1
Implement getRobotModel and getSerialNumber
URJala May 18, 2026
c894239
Implement commandShutdown
URJala May 18, 2026
59c411a
Implement commandAddToLog
URJala May 18, 2026
361b724
Add remaining endpoints to g_command_list
URJala May 18, 2026
6959ca1
Update tests
urfeex Aug 17, 2026
5ecd62b
Update docstring
urfeex Aug 17, 2026
60c4e79
Remove maybe_unused from add_to_log argument
urfeex Aug 17, 2026
2972cd8
Implement support file endpoints
urfeex Aug 17, 2026
675b382
Finalized Support file download
urfeex Aug 17, 2026
efca9b2
Add flight reports to version compatibility table
urfeex Aug 18, 2026
790ccf0
Merge remote-tracking branch 'origin/master' into robot_api_10.14
urfeex Aug 20, 2026
c57205d
Add 10.14 preview image to CI
urfeex Aug 20, 2026
f4b5268
Use RobotAPI version from preview image
urfeex Aug 21, 2026
42bab34
Changes from PR review
urfeex Aug 21, 2026
96b9eb4
Use httplib's response handler for downloading support files
urfeex Aug 21, 2026
d1e339a
Add workaround to handle ur7e and ur12e in tests correctly
urfeex Aug 21, 2026
45ba45c
Fix expected value
urfeex Aug 21, 2026
e7d6659
Download to tempfile to avoid overwriting when no data was fetched
urfeex Aug 21, 2026
e3dc459
Use json constructor instead of manually constructing json string
urfeex Aug 21, 2026
c01b3cb
Address minor issues
urfeex Aug 21, 2026
57e975b
Add mock tests for support files
urfeex Aug 21, 2026
d9b04f3
Add default implementation for commandDownloadSupportFiles
urfeex Aug 21, 2026
43bf03c
Use a new file for downloading the temp supportfiles
urfeex Aug 21, 2026
af5b0a1
Remove unused response
urfeex Aug 21, 2026
059c113
Add robot_api test to ignore list for maybe_uninitialized warnings
urfeex Aug 21, 2026
cc09f47
Harden against local-privilege symlink attacks
urfeex Aug 21, 2026
d5ac556
Fix comparison
urfeex Aug 21, 2026
103bf56
Use sopen_s instead of open on windows
urfeex Aug 21, 2026
0cc88d2
Check for write errors first
urfeex Aug 21, 2026
fde78fd
Fix minor typo
urfeex Aug 21, 2026
0b22f16
Fix using sopen_s
urfeex Aug 21, 2026
e17ed5b
Minor changes
urfeex Aug 21, 2026
9978847
Simplified windows path
urfeex Aug 21, 2026
9411d89
Fix close
urfeex Aug 21, 2026
e426a64
Replace shutdown test with mock test
urfeex Aug 21, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,11 @@ jobs:
PROGRAM_FOLDER: 'tests/resources/dockerursim/programs/polyscopex/10.13.0/ur7e'
POLYSCOPE_X_WITH_REMOTE_CONTROL: 'true'
CITADEL_DB_FOLDER: 'tests/resources/dockerursim/citadelDB'
- ROBOT_MODEL: 'ur7e'
URSIM_VERSION: '10.14.0-0.10.703-preview-1'
PROGRAM_FOLDER: 'tests/resources/dockerursim/programs/polyscopex/10.13.0/ur7e'
POLYSCOPE_X_WITH_REMOTE_CONTROL: 'true'
CITADEL_DB_FOLDER: 'tests/resources/dockerursim/citadelDB'

steps:
- uses: actions/checkout@v7
Expand Down
7 changes: 7 additions & 0 deletions doc/architecture/dashboard_client.rst
Original file line number Diff line number Diff line change
Expand Up @@ -80,3 +80,10 @@ Internally, the dashboard client makes calls against a RESTful (**Re**\ presenta
.. code-block:: json

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

The following commands are only available for PolyScope X robots and will throw a
``NotImplementedException`` when called on G5 (CB3 / PolyScope 5) robots:

- ``commandDownloadSupportFiles(save_path)``: Downloads support files from the robot as a zip
archive and saves them to the given path on the local machine. Available from PolyScope X
10.14.0 onward.
45 changes: 41 additions & 4 deletions doc/polyscope_compatibility.rst
Original file line number Diff line number Diff line change
Expand Up @@ -42,10 +42,47 @@ table below or checkout the latest tag before the breaking changes were introduc
|polyscope| X doesn't support all features supported by this library for |polyscope| 5.
Currently, the following components are known not to be supported:

- Dashboard client -- |polyscope| X received the first implementation of the Robot API
replacing the Dashboard Server in version 10.11.0. It covers robot state control and loading
and playing programs.
From version 10.12, it also supports uploading programs to the robot and downloading programs from the robot, as well as listing existing programs on the robot.
- Dashboard client -- |polyscope| X does not have a Dashboard server, but in version 10.11.0 introduced the Robot API, that fulfills some of the same purposes. The robot API has not yet reached feature parity with the Dashboard server.

- Implemented features, and their version requirements:

.. list-table::
:header-rows: 1

* - Introduced in |polyscope| version
- Functionality group
- examples
* - 10.11.0
- Robot state control
- power on, power off, brake release, etc
* - 10.11.0
- Load and play programs
- load program, play, pause, etc
* - 10.12.0
- Robot Program interactions
- Upload/update program, download program, list programs, etc
* - 10.12.0
- Get robot modes
- Robot mode, safety mode, operational mode, remote control
* - 10.14.0
- Popup interactions
- open, close, close safety popup
* - 10.14.0
- Get robot information
- Polyscope version, robot model, serial number
* - 10.14.0
- System control
- Shut down robot
* - 10.14.0
- Logging
- Add entry to system log
* - 10.14.0
- Flight reports
- Generating and downloading flight reports

- Using external control on |polyscope| X requires another URCapX for making external control
work. This is currently in the process of being created.
See `Universal Robots External Control URCapX <https://github.com/UniversalRobots/Universal_Robots_ExternalControl_URCapX>`_

.. |polyscope| replace:: PolyScope

Expand Down
30 changes: 26 additions & 4 deletions include/ur_client_library/ur/dashboard_client.h
Original file line number Diff line number Diff line change
Expand Up @@ -405,12 +405,12 @@ class DashboardClient
*
* \return True succeeded
*/
bool commandPopup(const std::string& popup_text);
bool commandPopup(const std::string& popup_text, const std::string& popup_title = "");
Comment thread
urfeex marked this conversation as resolved.

/*!
* \brief Send popup command
*/
DashboardResponse commandPopupWithResponse(const std::string& popup_text);
DashboardResponse commandPopupWithResponse(const std::string& popup_text, const std::string& popup_title = "");

/*!
* \brief Send text to log
Expand Down Expand Up @@ -676,7 +676,7 @@ class DashboardClient
*
* \return True succeeded
*/
bool commandGenerateFlightReport(const std::string& report_type);
bool commandGenerateFlightReport(const std::string& report_type = "");

/*!
* \brief Send Generate flight report command
Expand All @@ -685,7 +685,7 @@ class DashboardClient
*
* \param report_type The report type to set for the flight report
*/
DashboardResponse commandGenerateFlightReportWithResponse(const std::string& report_type);
DashboardResponse commandGenerateFlightReportWithResponse(const std::string& report_type = "");

/*!
* \brief Send Generate support file command
Expand All @@ -709,6 +709,28 @@ class DashboardClient
*/
DashboardResponse commandGenerateSupportFileWithResponse(const std::string& dir_path);

/*!
* \brief Download support files from the robot as a zip archive
*
* \note Only available for PolyScope X robots.
*
* \param save_path Filepath where the downloaded support file archive should be saved on the machine where the
* dashboard client is running.
*
* \return True on success
*/
bool commandDownloadSupportFiles(const std::string& save_path);

/*!
* \brief Download support files from the robot as a zip archive
*
* \note Only available for PolyScope X robots.
*
* \param save_path Filepath where the downloaded support file archive should be saved on the machine where the
* dashboard client is running.
*/
DashboardResponse commandDownloadSupportFilesWithResponse(const std::string& save_path);

/*!
* \brief Flush the polyscope log to the log_history.txt file
*
Expand Down
42 changes: 28 additions & 14 deletions include/ur_client_library/ur/dashboard_client_implementation.h
Original file line number Diff line number Diff line change
Expand Up @@ -61,8 +61,7 @@ struct ProgramInformation

inline std::ostream& operator<<(std::ostream& os, const ProgramInformation& pi)
{
os << "Program Information: { "
<< "\nCreated Date: " << pi.createdDate << "\nDescription: " << pi.description
os << "Program Information: { " << "\nCreated Date: " << pi.createdDate << "\nDescription: " << pi.description
<< "\nLast Modified Date: " << pi.lastModifiedDate << "\nLast Saved Date: " << pi.lastSavedDate
<< "\nName: " << pi.name << "\nProgram State: " << pi.programState << "\n} \n";
return os;
Expand Down Expand Up @@ -250,14 +249,14 @@ class DashboardClientImpl
/*!
* \brief Send Close popup command
*
* \throws an NotImplementedException when called on PolyScope X robots
* \throws an NotImplementedException when called on PolyScope X robots with version lower than 10.14.0
*/
virtual DashboardResponse commandClosePopup() = 0;

/*!
* \brief Send Close safety popup command
*
* \throws an NotImplementedException when called on PolyScope X robots
* \throws an NotImplementedException when called on PolyScope X robots with version lower than 10.14.0
*/
virtual DashboardResponse commandCloseSafetyPopup() = 0;

Expand All @@ -274,7 +273,7 @@ class DashboardClientImpl
/*!
* \brief Send Shutdown command
*
* \throws an NotImplementedException when called on PolyScope X robots
* \throws an NotImplementedException when called on PolyScope X robots with version lower than 10.14.0
*/
virtual DashboardResponse commandShutdown() = 0;

Expand Down Expand Up @@ -320,17 +319,19 @@ class DashboardClientImpl
* \brief Send popup command
*
* \param popup_text The text to be shown in the popup
* \param popup_title The title of the popup. This is optional and only used on PolyScope X
* robots.
*
* \throws an NotImplementedException when called on PolyScope X robots
* \throws an NotImplementedException when called on PolyScope X robots with software version lower than 10.14.0
*/
virtual DashboardResponse commandPopup(const std::string& popup_text) = 0;
virtual DashboardResponse commandPopup(const std::string& popup_text, const std::string& popup_title = "") = 0;
Comment thread
urfeex marked this conversation as resolved.
Comment thread
urfeex marked this conversation as resolved.

/*!
* \brief Send text to log
*
* \param log_text The text to be sent to the log
*
* \throws an NotImplementedException when called on PolyScope X robots
* \throws an NotImplementedException when called on PolyScope X robots with software version lower than 10.14.0
*/
virtual DashboardResponse commandAddToLog(const std::string& log_text) = 0;

Expand All @@ -341,7 +342,7 @@ class DashboardClientImpl
*
* - 'polyscope_version': std::string
*
* \throws an NotImplementedException when called on PolyScope X robots
* \throws an NotImplementedException when called on PolyScope X robots with software version lower than 10.14.0
*/
virtual DashboardResponse commandPolyscopeVersion() = 0;

Expand All @@ -352,7 +353,7 @@ class DashboardClientImpl
*
* - 'robot_model': std::string
*
* \throws an NotImplementedException when called on PolyScope X robots
* \throws an NotImplementedException when called on PolyScope X robots with software version lower than 10.14.0
*/
virtual DashboardResponse commandGetRobotModel() = 0;

Expand All @@ -363,7 +364,7 @@ class DashboardClientImpl
*
* - 'serial_number': std::string
*
* \throws an NotImplementedException when called on PolyScope X robots
* \throws an NotImplementedException when called on PolyScope X robots with software version lower than 10.14.0
*/
virtual DashboardResponse commandGetSerialNumber() = 0;

Expand Down Expand Up @@ -470,9 +471,10 @@ class DashboardClientImpl
*
* \param report_type The report type to set for the flight report
*
* \throws an NotImplementedException when called on PolyScope X robots
* \throws an NotImplementedException when called on PolyScope X robots with software version
* lower than 10.14.0
*/
virtual DashboardResponse commandGenerateFlightReport(const std::string& report_type) = 0;
virtual DashboardResponse commandGenerateFlightReport(const std::string& report_type = "") = 0;

/*!
* \brief Send Generate support file command
Expand All @@ -484,6 +486,18 @@ class DashboardClientImpl
*/
virtual DashboardResponse commandGenerateSupportFile(const std::string& dir_path) = 0;

/*!
* \brief Download support files from the robot as a zip archive
*
* \param save_path Filepath where the downloaded support file archive should be saved on the user's computer
*
* \throws an NotImplementedException when called on G5 robots
*/
virtual DashboardResponse commandDownloadSupportFiles([[maybe_unused]] const std::string& save_path)
{
throw NotImplementedException("commandDownloadSupportFiles is not implemented for this dashboard client.");
}

/*!
* \brief Flush the polyscope log to the log_history.txt file
*
Expand Down Expand Up @@ -544,7 +558,7 @@ class DashboardClientImpl
}

protected:
virtual void assertHasCommand(const std::string& command) const = 0;
virtual void assertHasCommand(const std::string& command) = 0;
Comment thread
urfeex marked this conversation as resolved.

VersionInformation polyscope_version_;
std::string host_;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -131,8 +131,9 @@ class DashboardClientImplG5 : public DashboardClientImpl, comm::TCPSocket
DashboardResponse commandClearOperationalMode() override;
DashboardResponse commandClosePopup() override;
DashboardResponse commandCloseSafetyPopup() override;
DashboardResponse commandGenerateFlightReport(const std::string& report_type) override;
DashboardResponse commandGenerateFlightReport(const std::string& report_type = "") override;
DashboardResponse commandGenerateSupportFile(const std::string& dir_path) override;
DashboardResponse commandDownloadSupportFiles(const std::string& save_path) override;
DashboardResponse commandGetLoadedProgram() override;
DashboardResponse commandGetOperationalMode() override;
DashboardResponse commandGetRobotModel() override;
Expand All @@ -146,7 +147,7 @@ class DashboardClientImplG5 : public DashboardClientImpl, comm::TCPSocket
DashboardResponse commandResume() override;
DashboardResponse commandPlay() override;
DashboardResponse commandPolyscopeVersion() override;
DashboardResponse commandPopup(const std::string& popup_text) override;
DashboardResponse commandPopup(const std::string& popup_text, const std::string& popup_title = "") override;
DashboardResponse commandPowerOff() override;
DashboardResponse commandPowerOn(const std::chrono::duration<double> timeout = std::chrono::seconds(300)) override;
DashboardResponse commandProgramState() override;
Expand Down Expand Up @@ -175,7 +176,7 @@ class DashboardClientImplG5 : public DashboardClientImpl, comm::TCPSocket

protected:
virtual VersionInformation queryPolyScopeVersion();
void assertHasCommand(const std::string& command) const override;
void assertHasCommand(const std::string& command) override;
static std::string replacePayload(const std::string& command, const std::string& payload);
std::string retryCommandString(const std::string& requestCommand, const std::string& requestExpectedResponse,
const std::string& waitRequest, const std::string& waitExpectedResponse,
Expand Down
24 changes: 21 additions & 3 deletions include/ur_client_library/ur/dashboard_client_implementation_x.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@

#pragma once

#include <atomic>
#include <unordered_map>

#include <ur_client_library/ur/dashboard_client_implementation.h>
#include "ur_client_library/ur/version_information.h"

Expand All @@ -42,6 +45,13 @@ class Result;
namespace urcl
{

struct RobotAPICommand
{
std::string endpoint;
VersionInformation robotAPIVersion;
VersionInformation marketingVersion;
};

class DashboardClientImplX : public DashboardClientImpl
{
public:
Expand Down Expand Up @@ -126,7 +136,8 @@ class DashboardClientImplX : public DashboardClientImpl
DashboardResponse commandClearOperationalMode() override;
DashboardResponse commandClosePopup() override;
DashboardResponse commandCloseSafetyPopup() override;
DashboardResponse commandGenerateFlightReport(const std::string& report_type) override;
DashboardResponse commandGenerateFlightReport(const std::string& report_type = "") override;
DashboardResponse commandDownloadSupportFiles(const std::string& save_path) override;
DashboardResponse commandGenerateSupportFile(const std::string& dir_path) override;
DashboardResponse commandGetLoadedProgram() override;
DashboardResponse commandGetOperationalMode() override;
Expand All @@ -141,7 +152,7 @@ class DashboardClientImplX : public DashboardClientImpl
DashboardResponse commandResume() override;
DashboardResponse commandPlay() override;
DashboardResponse commandPolyscopeVersion() override;
DashboardResponse commandPopup(const std::string& popup_text) override;
DashboardResponse commandPopup(const std::string& popup_text, const std::string& popup_title = "") override;
DashboardResponse commandPowerOff() override;
DashboardResponse commandPowerOn(const std::chrono::duration<double> timeout = std::chrono::seconds(300)) override;
DashboardResponse commandProgramState() override;
Expand Down Expand Up @@ -179,15 +190,22 @@ class DashboardClientImplX : public DashboardClientImpl
DashboardResponse put(const std::string& endpoint, const httplib::UploadFormDataItems& form_data,
const bool debug = true);
DashboardResponse get(const std::string& endpoint, const bool debug = true);

DashboardResponse del(const std::string& endpoint, const bool debug = true);

virtual VersionInformation queryPolyScopeVersion();
void assertHasCommand(const std::string& command) const override;
void assertHasCommand(const std::string& command) override;

const std::string base_url_ = "/universal-robots/robot-api";

std::unique_ptr<httplib::Client> cli_;
VersionInformation robot_api_version_;

timeval recv_timeout_ = { 10, 0 };
timeval send_timeout_ = { 10, 0 };

static std::unordered_map<std::string, RobotAPICommand> g_command_list;
Comment thread
urfeex marked this conversation as resolved.
std::atomic<bool> is_connected_{ false };
};

} // namespace urcl
19 changes: 15 additions & 4 deletions src/ur/dashboard_client.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -318,14 +318,15 @@ DashboardResponse DashboardClient::commandIsInRemoteControlWithResponse()
return impl_->commandIsInRemoteControl();
}

bool DashboardClient::commandPopup(const std::string& popup_text)
bool DashboardClient::commandPopup(const std::string& popup_text, const std::string& popup_title)
{
return commandPopupWithResponse(popup_text).ok;
return commandPopupWithResponse(popup_text, popup_title).ok;
}

DashboardResponse DashboardClient::commandPopupWithResponse(const std::string& popup_text)
DashboardResponse DashboardClient::commandPopupWithResponse(const std::string& popup_text,
const std::string& popup_title)
{
return impl_->commandPopup(popup_text);
return impl_->commandPopup(popup_text, popup_title);
}

bool DashboardClient::commandAddToLog(const std::string& log_text)
Expand Down Expand Up @@ -537,6 +538,16 @@ DashboardResponse DashboardClient::commandGenerateSupportFileWithResponse(const
return impl_->commandGenerateSupportFile(dir_path);
}

bool DashboardClient::commandDownloadSupportFiles(const std::string& save_path)
{
return commandDownloadSupportFilesWithResponse(save_path).ok;
}

DashboardResponse DashboardClient::commandDownloadSupportFilesWithResponse(const std::string& save_path)
{
return impl_->commandDownloadSupportFiles(save_path);
}

bool DashboardClient::commandSaveLog()
{
return commandSaveLogWithResponse().ok;
Expand Down
Loading
Loading