Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
11 changes: 6 additions & 5 deletions doc/architecture/primary_client.rst
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,11 @@ Method signature:
);

| The ``sendScriptBlocking`` method will also accept valid URScript code, but blocks until the execution result of the given program is available.
| Prior to transferring the program it will first check that the robot is in a state where it can execute programs, if not it returns false.
| Prior to transferring the program it will first check that the robot is in a state where it can execute programs, otherwise an exception is thrown.
| If the robot is ready, the program is then transferred, and the method will wait for the robot to report that the program has either started, finished or encountered an error.
| If the program has not started within the given ``timeout``, the method returns false.
| If the robot encounters an error or runtime exception during program execution the method also returns false.
| If ``fail_on_warnings`` is true, it will also return false, if the robot reports a warning during program execution. Note: protective stops are reported as warnings by the robot.
| The method only returns true if the program is successfully executed on the robot.
| If the program has not started within the given ``timeout``, the method throws an exception.
| If the robot encounters an error or runtime exception during program execution the method also throws an exception.
| If ``fail_on_warnings`` is true, it will also throw an exception, if the robot reports a warning during program execution. Note: protective stops are reported as warnings by the robot.
| If no exceptions are thrown, the script has been executed successfully.
| This method also accepts secondary programs, but no feedback is available for those, so it will behave similarly to the ``sendScript`` method in those cases, except for the pre-transfer checks.
| The exact exceptions that are thrown in various cases can be seen in the `primary client header file <https://github.com/UniversalRobots/Universal_Robots_Client_Library/blob/master/include/ur_client_library/primary/primary_client.h>`_.
31 changes: 18 additions & 13 deletions examples/send_script.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,13 +45,10 @@ def example_fun():
relative_move = p[0,-0.1,0,0,0,0]
movel(pose_trans(current_pose, relative_move), t=1)
end)""";

if (client.sendScriptBlocking(fully_defined_script))
{
// The function definition can also be omitted
// A function name will then be auto generated
client.sendScriptBlocking(R"(textmsg("Successful program execution"))");
}
client.sendScriptBlocking(fully_defined_script);
// The function definition can also be omitted
// A function name will then be auto generated
client.sendScriptBlocking(R"(textmsg("Successful program execution"))");
// A script-function name can also be passed to the method
// A timeout can also be given to limit the wait for the passed function to start. If timeout = 0, it will
// wait indefinitely.
Expand All @@ -66,18 +63,26 @@ end
)";
client.sendScriptBlocking(secondary_script);

// Sending wrong script code will result in a clear error
// Sending wrong script code will result in an exception with a clear explanation
const std::string bad_script_code = R"""(
def bad_code():
current_pose = get_target_tcp_pose()
movel(current_pos) # note pose vs pos
end)""";
URCL_LOG_INFO("Sending bad script code...");
bool success = client.sendScriptBlocking(bad_script_code);
try
{
std::stringstream ss;
ss << "Execution of bad code successful? " << std::boolalpha << success;
URCL_LOG_INFO("%s", ss.str().c_str());
client.sendScriptBlocking(bad_script_code);
}
catch (const RobotRuntimeException& exc)
{
URCL_LOG_INFO("Caught expected runtime exception from sendScriptBlocking");
URCL_LOG_INFO(exc.what());
}
catch (const UrException& exc)
{
URCL_LOG_ERROR("Caught unexpected exception from sendScriptBlocking");
URCL_LOG_ERROR(exc.what());
}

// We can also send script code without any checks
Expand All @@ -87,7 +92,7 @@ end)""";
// E.g. sending the bad script here will not give us any information
// The return value will only tell us that the script code has been sent to the robot.
URCL_LOG_INFO("Sending bad script code without feedback...");
success = client.sendScript(bad_script_code);
bool success = client.sendScript(bad_script_code);
{
std::stringstream ss;
ss << "Bad code sent to robot successfully? " << std::boolalpha << success;
Expand Down
130 changes: 130 additions & 0 deletions include/ur_client_library/exceptions.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,9 @@
#include <optional>
#include <stdexcept>
#include <sstream>
#include <vector>
#include "ur/version_information.h"
#include "ur_client_library/ur/datatypes.h"

#ifdef _WIN32
# define NOMINMAX
Expand Down Expand Up @@ -336,5 +338,133 @@ class ScriptCodeSyntaxException : public UrException
return std::runtime_error::what();
}
};

class RobotModeException : public UrException
{
public:
explicit RobotModeException() = delete;

explicit RobotModeException(const std::string& operation, const RobotMode& required, const RobotMode& actual)
: std::runtime_error("Incorrect robot mode: " + robotModeString(actual))
{
std::stringstream ss;
ss << "Robot is in incorrect mode for the requested operation: " << operation << "\n"
<< "Required robot mode: " << urcl::robotModeString(required) << " (" << int(required) << ") \n"
<< "Actual robot mode: " << urcl::robotModeString(actual) << " (" << int(actual) << ")";
text_ = ss.str();
}

virtual ~RobotModeException() = default;

virtual const char* what() const noexcept override
{
return text_.c_str();
}

private:
std::string text_;
};

class SafetyModeException : public UrException
{
public:
explicit SafetyModeException() = delete;

explicit SafetyModeException(const std::string& operation, const std::vector<urcl::SafetyMode>& options,
const urcl::SafetyMode& actual)
: std::runtime_error("Incorrect safety mode: " + safetyModeString(actual))
{
std::stringstream ss;
ss << "Robot is in incorrect safety mode for the requested operation: " << operation << "\n"
<< "Safety mode should be one of: \n";

for (auto mode : options)
{
ss << urcl::safetyModeString(mode) << " (" << int(mode) << ")\n";
}
ss << "\n"
<< "Actual safety mode: " << urcl::safetyModeString(actual) << " (" << int(actual) << ")";
text_ = ss.str();
}

virtual ~SafetyModeException() = default;

virtual const char* what() const noexcept override
{
return text_.c_str();
}

private:
std::string text_;
};

class StreamNotConnectedException : public UrException
{
public:
explicit StreamNotConnectedException() = delete;

explicit StreamNotConnectedException(const std::string& text) : std::runtime_error(text)
{
}

virtual ~StreamNotConnectedException() = default;

virtual const char* what() const noexcept override
{
return std::runtime_error::what();
}
};

class RobotRuntimeException : public UrException
{
public:
explicit RobotRuntimeException() = delete;

explicit RobotRuntimeException(const std::string& text) : std::runtime_error(text)
{
}

virtual ~RobotRuntimeException() = default;

virtual const char* what() const noexcept override
{
return std::runtime_error::what();
}
};

class ReadOnlyInterfaceException : public UrException
{
public:
explicit ReadOnlyInterfaceException() = delete;

explicit ReadOnlyInterfaceException(const std::string& text) : std::runtime_error(text)
{
}

virtual ~ReadOnlyInterfaceException() = default;

virtual const char* what() const noexcept override
{
return std::runtime_error::what();
}
};

class RobotErrorCodeException : public UrException
{
public:
explicit RobotErrorCodeException() = delete;

explicit RobotErrorCodeException(const std::string& text) : std::runtime_error(text)
{
}

virtual ~RobotErrorCodeException() = default;

virtual const char* what() const noexcept override
{
return std::runtime_error::what();
}
};

} // namespace urcl
#endif // ifndef UR_CLIENT_LIBRARY_EXCEPTIONS_H_INCLUDED
15 changes: 11 additions & 4 deletions include/ur_client_library/primary/primary_client.h
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ class PrimaryClient
* The given code must be valid according the UR Scripting Manual. The given script code will be automatically wrapped
* in a function definition, if it is not already. Secondary programs can also be passed to this function, but must be
* fully defined as a secondary program when calling. Secondary programs create no feedback, so this function will
* return true as soon as the program is uploaded successfully to the robot (same as the sendScript function).
* return as soon as the program is uploaded successfully to the robot (same as the sendScript function).
*
* \param program URScript code that shall be executed by the robot.
*
Expand All @@ -126,10 +126,17 @@ class PrimaryClient
* \throw urcl::ScriptCodeSyntaxException if the given script code has syntax errors, which are checked here.
* \throw urcl::UrException if the stop command cannot be sent to the robot.
* \throw urcl::TimeoutException if the robot doesn't stop the program within the given timeout.
*
* \returns true on successful execution of the script, false otherwise
* \throw urcl::TimeoutException if the robot mode is not received within 1 second.
* \throw urcl::TimeoutException if the program does not start within the given timeout.
* \throw urcl::RobotModeException if the robot is in an incorrect mode for script execution.
* \throw urcl::SafetyModeException if the robot is in an incorrect safety mode for script execution
* \throw urcl::StreamNotConnectedException if the script cannot be transferred to the robot.
* \throw urcl::RobotRuntimeException if the given script causes a runtime exception on the robot.
* \throw urcl::ReadOnlyInterfaceException if the primary interface is in read-only mode when the script is
* transferred. This can happen if the robot was recently switched from manual to remote control mode.
* \throw urcl::RobotErrorCodeException if the robot encounters an error during script execution.
*/
bool sendScriptBlocking(const std::string& program, std::string script_name = "",
void sendScriptBlocking(const std::string& program, std::string script_name = "",
std::chrono::milliseconds start_timeout = std::chrono::seconds(1),
bool fail_on_warnings = true);

Expand Down
23 changes: 12 additions & 11 deletions include/ur_client_library/primary/primary_consumer.h
Original file line number Diff line number Diff line change
Expand Up @@ -136,23 +136,24 @@ class PrimaryConsumer : public AbstractPrimaryConsumer

switch (code.report_level)
{
case urcl::primary_interface::ReportLevel::DEBUG:
case urcl::primary_interface::ReportLevel::DEVL_DEBUG:
case urcl::primary_interface::ReportLevel::DEVL_INFO:
case urcl::primary_interface::ReportLevel::DEVL_WARNING:
case urcl::primary_interface::ReportLevel::DEVL_VIOLATION:
case urcl::primary_interface::ReportLevel::DEVL_FAULT:
case ReportLevel::DEBUG:
case ReportLevel::DEVL_DEBUG:
case ReportLevel::DEVL_INFO:
case ReportLevel::DEVL_WARNING:
case ReportLevel::DEVL_VIOLATION:
case ReportLevel::DEVL_FAULT:
case ReportLevel::DEVL_CRITICAL_FAULT:
URCL_LOG_DEBUG(log_contents.c_str());
break;
case urcl::primary_interface::ReportLevel::INFO:
case ReportLevel::INFO:
URCL_LOG_INFO(log_contents.c_str());
break;
case urcl::primary_interface::ReportLevel::WARNING:
case ReportLevel::WARNING:
URCL_LOG_WARN(log_contents.c_str());
break;
default:
// urcl::primary_interface::ReportLevel::VIOLATION:
// urcl::primary_interface::ReportLevel::FAULT:
case ReportLevel::VIOLATION:
case ReportLevel::FAULT:
case ReportLevel::CRITICAL_FAULT:
URCL_LOG_ERROR(log_contents.c_str());
break;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,24 +29,12 @@
#define UR_CLIENT_LIBRARY_PRIMARY_ERROR_CODE_MESSAGE_H_INCLUDED

#include "ur_client_library/primary/robot_message.h"
#include "ur_client_library/ur/datatypes.h"

namespace urcl
{
namespace primary_interface
{
enum class ReportLevel : int32_t
{
DEBUG = 0,
INFO = 1,
WARNING = 2,
VIOLATION = 3,
FAULT = 4,
DEVL_DEBUG = 128,
DEVL_INFO = 129,
DEVL_WARNING = 130,
DEVL_VIOLATION = 131,
DEVL_FAULT = 132
};

struct ErrorCode
{
Expand Down
48 changes: 48 additions & 0 deletions include/ur_client_library/ur/datatypes.h
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,54 @@ enum class RobotSeries
UR_SERIES = 3
};

enum class ReportLevel : int32_t
{
DEBUG = 0,
INFO = 1,
WARNING = 2,
VIOLATION = 3,
FAULT = 4,
CRITICAL_FAULT = 5,
DEVL_DEBUG = 128,
DEVL_INFO = 129,
DEVL_WARNING = 130,
DEVL_VIOLATION = 131,
DEVL_FAULT = 132,
DEVL_CRITICAL_FAULT = 133
};

inline std::string reportLevelString(const ReportLevel& code)
{
switch (code)
{
case ReportLevel::DEBUG:
return "DEBUG";
case ReportLevel::INFO:
return "INFO";
case ReportLevel::WARNING:
return "WARNING";
case ReportLevel::VIOLATION:
return "VIOLATION";
case ReportLevel::FAULT:
return "FAULT";
case ReportLevel::CRITICAL_FAULT:
return "CRITICAL_FAULT";
case ReportLevel::DEVL_DEBUG:
return "DEVL_DEBUG";
case ReportLevel::DEVL_INFO:
return "DEVL_INFO";
case ReportLevel::DEVL_WARNING:
return "DEVL_WARNING";
case ReportLevel::DEVL_VIOLATION:
return "DEVL_VIOLATION";
case ReportLevel::DEVL_FAULT:
return "DEVL_FAULT";
case ReportLevel::DEVL_CRITICAL_FAULT:
return "DEVL_CRITICAL_FAULT";
}
throw std::invalid_argument("Unknown report level: " + std::to_string(static_cast<int>(code)));
}

inline std::string robotModeString(const RobotMode& mode)
{
switch (mode)
Expand Down
Loading
Loading