Skip to content

Commit 387b21d

Browse files
urmahpfmauch
andauthored
Support starting the driver, before the robot is booted (UniversalRobots#98)
* Support starting the driver, before the robot is booted Refactored client library to support starting the client, before the robot is booted. Changed producer to wait until robot is reachable on configured IP, instead of throwing an exception. * Move the endless connection attempts to the tcp socket This will enable the dashboard client and secondary client to wait for a robot to be booted * Fix formatting. Co-authored-by: Felix Exner <[email protected]>
1 parent c12652f commit 387b21d

File tree

8 files changed

+341
-54
lines changed

8 files changed

+341
-54
lines changed

.gitignore

+2-1
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,5 @@ install_manifest.txt
66
*~
77
.idea
88
.directory
9-
.vscode
9+
.vscode
10+
build/

include/ur_client_library/comm/stream.h

+10
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,16 @@ class URStream : public TCPSocket
104104
*/
105105
bool write(const uint8_t* buf, const size_t buf_len, size_t& written);
106106

107+
/*!
108+
* \brief Get the host IP
109+
*
110+
* \returns The host IP
111+
*/
112+
std::string getHost()
113+
{
114+
return host_;
115+
}
116+
107117
protected:
108118
virtual bool open(int socket_fd, struct sockaddr* address, size_t address_len)
109119
{

include/ur_client_library/rtde/control_package_pause.h

+12
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,18 @@ class ControlPackagePauseRequest : public RTDEPackage
8282
{
8383
}
8484
virtual ~ControlPackagePauseRequest() = default;
85+
86+
/*!
87+
* \brief Generates a serialized package.
88+
*
89+
* \param buffer Buffer to fill with the serialization
90+
*
91+
* \returns The total size of the serialized package
92+
*/
93+
static size_t generateSerializedRequest(uint8_t* buffer);
94+
95+
private:
96+
static const uint16_t PAYLOAD_SIZE = 0;
8597
};
8698

8799
} // namespace rtde_interface

include/ur_client_library/rtde/rtde_client.h

+35
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ namespace rtde_interface
5151
{
5252
static const uint16_t MAX_RTDE_PROTOCOL_VERSION = 2;
5353
static const unsigned MAX_REQUEST_RETRIES = 5;
54+
static const unsigned MAX_INITIALIZE_ATTEMPTS = 10;
5455

5556
enum class UrRtdeRobotStatusBits
5657
{
@@ -75,6 +76,15 @@ enum class UrRtdeSafetyStatusBits
7576
IS_STOPPED_DUE_TO_SAFETY = 10
7677
};
7778

79+
enum class ClientState
80+
{
81+
UNINITIALIZED = 0,
82+
INITIALIZING = 1,
83+
INITIALIZED = 2,
84+
RUNNING = 3,
85+
PAUSED = 4
86+
};
87+
7888
/*!
7989
* \brief The RTDEClient class manages communication over the RTDE interface. It contains the RTDE
8090
* handshake and read and write functionality to and from the robot.
@@ -109,6 +119,12 @@ class RTDEClient
109119
* \returns Success of the requested start
110120
*/
111121
bool start();
122+
/*!
123+
* \brief Pauses RTDE data package communication
124+
*
125+
* \returns Wheter the RTDE data package communication was paussed succesfully
126+
*/
127+
bool pause();
112128
/*!
113129
* \brief Reads the pipeline to fetch the next data package.
114130
*
@@ -177,15 +193,34 @@ class RTDEClient
177193
double max_frequency_;
178194
double target_frequency_;
179195

196+
ClientState client_state_;
197+
180198
constexpr static const double CB3_MAX_FREQUENCY = 125.0;
181199
constexpr static const double URE_MAX_FREQUENCY = 500.0;
182200

183201
std::vector<std::string> readRecipe(const std::string& recipe_file);
184202

203+
void setupCommunication();
185204
bool negotiateProtocolVersion(const uint16_t protocol_version);
186205
void queryURControlVersion();
187206
void setupOutputs(const uint16_t protocol_version);
188207
void setupInputs();
208+
void disconnect();
209+
210+
/*!
211+
* \brief Checks wheter the robot is booted, this is done by looking at the timestamp from the robot controller, this
212+
* will show the time in seconds since the controller was started. If the timestamp is below 40, we will read from
213+
* the stream for approximately 1 second to ensure that the RTDE interface is up and running. This will ensure that we
214+
* don't finalize setting up communication, before the controller is up and running. Else we could end up connecting
215+
* to the RTDE interface, before a restart occurs during robot boot which would then destroy the connection
216+
* established.
217+
*
218+
* \returns true if the robot is booted, false otherwise which will essentially trigger a reconnection.
219+
*/
220+
bool isRobotBooted();
221+
bool sendStart();
222+
bool sendPause();
223+
189224
/*!
190225
* \brief Splits a variable_types string as reported from the robot into single variable type
191226
* strings

src/comm/tcp_socket.cpp

+30-25
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@
2525
#include <netinet/tcp.h>
2626
#include <unistd.h>
2727
#include <cstring>
28+
#include <sstream>
29+
#include <thread>
2830

2931
#include "ur_client_library/log.h"
3032
#include "ur_client_library/comm/tcp_socket.h"
@@ -72,38 +74,41 @@ bool TCPSocket::setup(std::string& host, int port)
7274
hints.ai_socktype = SOCK_STREAM;
7375
hints.ai_flags = AI_PASSIVE;
7476

75-
if (getaddrinfo(host_name, service.c_str(), &hints, &result) != 0)
76-
{
77-
URCL_LOG_ERROR("Failed to get address for %s:%d", host.c_str(), port);
78-
return false;
79-
}
80-
8177
bool connected = false;
82-
// loop through the list of addresses untill we find one that's connectable
83-
for (struct addrinfo* p = result; p != nullptr; p = p->ai_next)
78+
while (!connected)
8479
{
85-
socket_fd_ = ::socket(p->ai_family, p->ai_socktype, p->ai_protocol);
86-
87-
if (socket_fd_ != -1 && open(socket_fd_, p->ai_addr, p->ai_addrlen))
80+
if (getaddrinfo(host_name, service.c_str(), &hints, &result) != 0)
8881
{
89-
connected = true;
90-
break;
82+
URCL_LOG_ERROR("Failed to get address for %s:%d", host.c_str(), port);
83+
return false;
9184
}
92-
}
85+
// loop through the list of addresses untill we find one that's connectable
86+
for (struct addrinfo* p = result; p != nullptr; p = p->ai_next)
87+
{
88+
socket_fd_ = ::socket(p->ai_family, p->ai_socktype, p->ai_protocol);
9389

94-
freeaddrinfo(result);
90+
if (socket_fd_ != -1 && open(socket_fd_, p->ai_addr, p->ai_addrlen))
91+
{
92+
connected = true;
93+
break;
94+
}
95+
}
9596

96-
if (!connected)
97-
{
98-
state_ = SocketState::Invalid;
99-
URCL_LOG_ERROR("Connection setup failed for %s:%d", host.c_str(), port);
100-
}
101-
else
102-
{
103-
setOptions(socket_fd_);
104-
state_ = SocketState::Connected;
105-
URCL_LOG_DEBUG("Connection established for %s:%d", host.c_str(), port);
97+
freeaddrinfo(result);
98+
99+
if (!connected)
100+
{
101+
state_ = SocketState::Invalid;
102+
std::stringstream ss;
103+
ss << "Failed to connect to robot on IP " << host_name
104+
<< ". Please check that the robot is booted and reachable on " << host_name << ". Retrying in 10 seconds";
105+
URCL_LOG_ERROR("%s", ss.str().c_str());
106+
std::this_thread::sleep_for(std::chrono::seconds(10));
107+
}
106108
}
109+
setOptions(socket_fd_);
110+
state_ = SocketState::Connected;
111+
URCL_LOG_DEBUG("Connection established for %s:%d", host.c_str(), port);
107112
return connected;
108113
}
109114

src/rtde/control_package_pause.cpp

+6
Original file line numberDiff line numberDiff line change
@@ -45,5 +45,11 @@ std::string ControlPackagePause::toString() const
4545

4646
return ss.str();
4747
}
48+
49+
size_t ControlPackagePauseRequest::generateSerializedRequest(uint8_t* buffer)
50+
{
51+
return PackageHeader::serializeHeader(buffer, PackageType::RTDE_CONTROL_PACKAGE_PAUSE, PAYLOAD_SIZE);
52+
}
53+
4854
} // namespace rtde_interface
4955
} // namespace urcl

0 commit comments

Comments
 (0)