A C++ library for accessing Universal Robots interfaces. With this library C++-based drivers can be implemented in order to create external applications leveraging the versatility of Universal Robots robotic manipulators.
- Polyscope (The software running on the robot controller) version 3.14.3 (for CB3-Series), or 5.9.4 (for e-Series) or higher. If you use an older Polyscope version it is suggested to update your robot. If for some reason (please tell us in the issues why) you cannot upgrade your robot, please see the version compatibility table for a compatible tag.
- The library requires an implementation of POSIX threads such as the
pthread
library - Socket communication is currently based on Linux sockets. Thus, this library will require Linux for building and using.
- The master branch of this repository requires a C++17-compatible compiler. For building this library without a C++17-requirement, please use the boost branch instead that requires the boost library.
The majority of this library is licensed under the Apache-2.0 licensed. However, certain parts are licensed under different licenses:
- The queue used inside the communication structures is originally written by Cameron Desrochers and is released under the BSD-2-Clause license.
- The semaphore implementation used inside the queue implementation is written by Jeff Preshing and licensed under the zlib license
- The Dockerfile used for the integration tests of this repository is originally written by Arran Hobson Sayers and released under the MIT license
While the main LICENSE
file in this repository contains the Apache-2.0 license used for the
majority of the work, the respective libraries of third-party components reside together with the
code imported from those third parties.
Currently, this library contains the following components:
- Basic primary interface: The primary interface isn't fully implemented at the current state and provides only basic functionality. See A word on the primary / secondary interface for further information about the primary interface.
- RTDE interface: The RTDE interface is fully supported by this library. See RTDEClient for further information on how to use this library as an RTDE client.
- Dashboard interface: The Dashboard server can be accessed directly from C++ through helper functions using this library.
- Custom motion streaming: This library was initially developed as part of the Universal Robots ROS driver. Therefore, it also contains a mechanism to do data streaming through a custom socket, e.g. to perform motion command streaming.
In the examples
subfolder you will find a minimal example of a running driver. It starts an
instance of the UrDriver
class and prints the RTDE values read from the controller. To run it make
sure to
- have an instance of a robot controller / URSim running at the configured IP address (or adapt the address to your needs)
- run it from the package's main folder (the one where this README.md file is stored), as for simplicity reasons it doesn't use any sophisticated method to locate the required files.
See Architecture documentation
Currently, this library doesn't support the primary interface very well, as the Universal Robots
ROS driver was built mainly upon
the RTDE interface. Therefore, there is also no PrimaryClient
for directly accessing the primary
interface. This may change in future, though.
The comm::URStream
class can be used to open a connection to the primary / secondary interface
and send data to it. The producer/consumer pipeline structure
can also be used together with the primary / secondary interface. However, package parsing isn't
implemented for most packages currently. See the primary_pipeline
example on details how to set this up. Note that when running this
example, most packages will just be printed as their raw byte streams in a hex notation, as they
aren't implemented in the library, yet.
As mentioned above, for a clean operation it is quite critical that arriving RTDE messages are read
before the next message arrives. Due to this, both, the RTDE receive thread and the thread calling
getDataPackage()
should be scheduled with real-time priority. See this guide
for details on how to set this up.
The RTDE receive thread will be scheduled to real-time priority automatically, if applicable. If
this doesn't work, an error is raised at startup. The main thread calling getDataPackage
should be
scheduled to real-time priority by the application. See the
ur_robot_driver
as an example.
Communication with the primary / secondary and RTDE interfaces is designed to use a
consumer/producer pattern. The Producer reads data from the socket whenever it comes in, parses the
contents and stores the parsed packages into a pipeline queue.
You can write your own consumers that use the packages coming from the producer. See the
comm::ShellConsumer
as an example.
As this library was originally designed to be included into a ROS driver but also to be used as a
standalone library, it uses custom logging macros instead of direct printf
or std::cout
statements.
The macro based interface is by default using the DefaultLogHandler
to print the logging messages as printf
statements. It is possible to define your own log handler
to change the behavior, see create new log handler on how to.
Make sure to set the logging level in your application, as by default only messages of level WARNING or higher will be printed. See below for an example:
#include "ur_client_library/log.h"
int main(int argc, char* argv[])
{
urcl::setLogLevel(urcl::LogLevel::DEBUG);
URCL_LOG_DEBUG("Logging debug message");
return 0;
}
The logger comes with an interface LogHandler
, which can be
used to implement your own log handler for messages logged with this library. This can be done by
inheriting from the LogHandler class
.
If you want to create a new log handler in your application, you can use below example as inspiration:
#include "ur_client_library/log.h"
#include <iostream>
class MyLogHandler : public urcl::LogHandler
{
public:
MyLogHandler() = default;
void log(const char* file, int line, urcl::LogLevel loglevel, const char* log) override
{
switch (loglevel)
{
case urcl::LogLevel::INFO:
std::cout << "INFO " << file << " " << line << ": " << log << std::endl;
break;
case urcl::LogLevel::DEBUG:
std::cout << "DEBUG " << file << " " << line << ": " << log << std::endl;
break;
case urcl::LogLevel::WARN:
std::cout << "WARN " << file << " " << line << ": " << log << std::endl;
break;
case urcl::LogLevel::ERROR:
std::cout << "ERROR " << file << " " << line << ": " << log << std::endl;
break;
case urcl::LogLevel::FATAL:
std::cout << "ERROR " << file << " " << line << ": " << log << std::endl;
break;
default:
break;
}
}
};
int main(int argc, char* argv[])
{
urcl::setLogLevel(urcl::LogLevel::DEBUG);
std::unique_ptr<MyLogHandler> log_handler(new MyLogHandler);
urcl::registerLogHandler(std::move(log_handler));
URCL_LOG_DEBUG("logging debug message");
URCL_LOG_INFO("logging info message");
return 0;
}
-
This repo supports pre-commit e.g. for automatic code formatting. TLDR: This will prevent you from committing falsely formatted code:
pipx install pre-commit pre-commit install
-
Succeeding pipelines are a must on Pull Requests (unless there is a reason, e.g. when there have been upstream changes).
-
We try to increase and keep our code coverage high, so PRs with new features should also have tests covering them.
-
Parameters of public methods must all be documented.
Many parts of this library are forked from the ur_modern_driver.
Developed in collaboration between:
Supported by ROSIN - ROS-Industrial Quality-Assured Robot Software Components. More information: rosin-project.eu
This project has received funding from the European Union’s Horizon 2020 research and innovation programme under grant agreement no. 732287.