forked from UniversalRobots/Universal_Robots_Client_Library
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathrtde_client.h
More file actions
318 lines (285 loc) · 11 KB
/
Copy pathrtde_client.h
File metadata and controls
318 lines (285 loc) · 11 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
// this is for emacs file handling -*- mode: c++; indent-tabs-mode: nil -*-
// -- BEGIN LICENSE BLOCK ----------------------------------------------
// Copyright 2019 FZI Forschungszentrum Informatik
// Created on behalf of Universal Robots A/S
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// -- END LICENSE BLOCK ------------------------------------------------
//----------------------------------------------------------------------
/*!\file
*
* \author Tristan Schnell schnell@fzi.de
* \date 2019-04-10
*
*/
//----------------------------------------------------------------------
#ifndef UR_CLIENT_LIBRARY_RTDE_CLIENT_H_INCLUDED
#define UR_CLIENT_LIBRARY_RTDE_CLIENT_H_INCLUDED
#include <memory>
#include "ur_client_library/comm/pipeline.h"
#include "ur_client_library/rtde/package_header.h"
#include "ur_client_library/rtde/rtde_package.h"
#include "ur_client_library/comm/stream.h"
#include "ur_client_library/rtde/rtde_parser.h"
#include "ur_client_library/comm/producer.h"
#include "ur_client_library/rtde/data_package.h"
#include "ur_client_library/rtde/request_protocol_version.h"
#include "ur_client_library/rtde/control_package_setup_outputs.h"
#include "ur_client_library/rtde/control_package_start.h"
#include "ur_client_library/log.h"
#include "ur_client_library/rtde/rtde_writer.h"
static const int UR_RTDE_PORT = 30004;
static const std::string PIPELINE_NAME = "RTDE Data Pipeline";
namespace urcl
{
namespace rtde_interface
{
static const uint16_t MAX_RTDE_PROTOCOL_VERSION = 2;
static const unsigned MAX_REQUEST_RETRIES = 5;
enum class UrRtdeRobotStatusBits
{
IS_POWER_ON = 0,
IS_PROGRAM_RUNNING = 1,
IS_TEACH_BUTTON_PRESSED = 2,
IS_POWER_BUTTON_PRESSED = 3
};
enum class UrRtdeSafetyStatusBits
{
IS_NORMAL_MODE = 0,
IS_REDUCED_MODE = 1,
IS_PROTECTIVE_STOPPED = 2,
IS_RECOVERY_MODE = 3,
IS_SAFEGUARD_STOPPED = 4,
IS_SYSTEM_EMERGENCY_STOPPED = 5,
IS_ROBOT_EMERGENCY_STOPPED = 6,
IS_EMERGENCY_STOPPED = 7,
IS_VIOLATION = 8,
IS_FAULT = 9,
IS_STOPPED_DUE_TO_SAFETY = 10,
IS_3PE_INPUT_ACTIVE = 11
};
enum class ClientState
{
UNINITIALIZED = 0,
INITIALIZING = 1,
INITIALIZED = 2,
RUNNING = 3,
PAUSED = 4
};
/*!
* \brief The RTDEClient class manages communication over the RTDE interface. It contains the RTDE
* handshake and read and write functionality to and from the robot.
*/
class RTDEClient
{
public:
RTDEClient() = delete;
/*!
* \brief Creates a new RTDEClient object, including a used URStream and Pipeline to handle the
* communication with the robot.
*
* \param robot_ip The IP of the robot
* \param notifier The notifier to use in the pipeline
* \param output_recipe_file Path to the file containing the output recipe
* \param input_recipe_file Path to the file containing the input recipe
* \param target_frequency Frequency to run at. Defaults to 0.0 which means maximum frequency.
* \param ignore_unavailable_outputs Configure the behaviour when a variable of the output recipe is not available
* from the robot: output is silently ignored if true, a UrException is raised otherwise.
*/
RTDEClient(std::string robot_ip, comm::INotifier& notifier, const std::string& output_recipe_file,
const std::string& input_recipe_file, double target_frequency = 0.0,
bool ignore_unavailable_outputs = false);
/*!
* \brief Creates a new RTDEClient object, including a used URStream and Pipeline to handle the
* communication with the robot.
*
* \param robot_ip The IP of the robot
* \param notifier The notifier to use in the pipeline
* \param output_recipe Vector containing the output recipe
* \param input_recipe Vector containing the input recipe
* \param target_frequency Frequency to run at. Defaults to 0.0 which means maximum frequency.
* \param ignore_unavailable_outputs Configure the behaviour when a variable of the output recipe is not available
* from the robot: output is silently ignored if true, a UrException is raised otherwise.
*/
RTDEClient(std::string robot_ip, comm::INotifier& notifier, const std::vector<std::string>& output_recipe,
const std::vector<std::string>& input_recipe, double target_frequency = 0.0,
bool ignore_unavailable_outputs = false);
~RTDEClient();
/*!
* \brief Sets up RTDE communication with the robot. The handshake includes negotiation of the
* used protocol version and setting of input and output recipes.
*
* \param max_connection_attempts Maximum number of (socket) connection attempts before counting the connection as
* failed. Unlimited number of attempts when set to 0.
* \param reconnection_timeout Time in between connection attempts to the socket
* \param max_initialization_attempts Maximum number of initialization attempts before counting
* the initialization as failed. Initialization can
* fail given an established socket connection e.g. when the connected socket does not implement
* an RTDE interface.
* \param initialization_timeout Time in between initialization attempts of the RTDE interface
*
* \returns Success of the handshake
*/
bool init(const size_t max_connection_attempts = 0,
const std::chrono::milliseconds reconnection_timeout = comm::TCPSocket::DEFAULT_RECONNECTION_TIME,
const size_t max_initialization_attempts = 3,
const std::chrono::milliseconds initialization_timeout = std::chrono::seconds(1));
/*!
* \brief Triggers the robot to start sending RTDE data packages in the negotiated format.
*
* \returns Success of the requested start
*/
bool start();
/*!
* \brief Pauses RTDE data package communication
*
* \returns Whether the RTDE data package communication was paused successfully
*/
bool pause();
/*!
* \brief Reads the pipeline to fetch the next data package.
*
* \param timeout Time to wait if no data package is currently in the queue
*
* \returns Unique ptr to the package, if a package was fetched successfully, nullptr otherwise
*/
std::unique_ptr<rtde_interface::DataPackage> getDataPackage(std::chrono::milliseconds timeout);
/*!
* \brief Getter for the maximum frequency the robot can publish RTDE data packages with.
*
* \returns The maximum frequency
*/
double getMaxFrequency() const
{
return max_frequency_;
}
/*!
* \brief Getter for the target frequency that the robot will publish RTDE data packages with.
*
* \returns The target frequency
*/
double getTargetFrequency() const
{
return target_frequency_;
}
/*!
* \brief Getter for the UR control version received from the robot.
*
* \returns The VersionInformation received from the robot
*/
VersionInformation getVersion()
{
return urcontrol_version_;
}
/*!
* \brief Returns the IP address (of the machine running this driver) used for the socket connection.
*
* \returns The IP address as a string (e.g. "192.168.0.1")
*/
std::string getIP() const;
/*!
* \brief Getter for the RTDE writer, which is used to send data via the RTDE interface to the
* robot.
*
* \returns A reference to the used RTDEWriter
*/
RTDEWriter& getWriter();
/*!
* \brief Getter for the RTDE output recipe.
*
* \returns The output recipe
*/
std::vector<std::string> getOutputRecipe()
{
return output_recipe_;
}
/*!
* \brief Getter for the RTDE input recipe.
*
* \returns The input recipe
*/
std::vector<std::string> getInputRecipe()
{
return input_recipe_;
}
// Reads output or input recipe from a file
static std::vector<std::string> readRecipe(const std::string& recipe_file);
private:
comm::URStream<RTDEPackage> stream_;
std::vector<std::string> output_recipe_;
bool ignore_unavailable_outputs_;
std::vector<std::string> input_recipe_;
RTDEParser parser_;
std::unique_ptr<comm::URProducer<RTDEPackage>> prod_;
comm::INotifier notifier_;
std::unique_ptr<comm::Pipeline<RTDEPackage>> pipeline_;
RTDEWriter writer_;
std::atomic<bool> reconnecting_;
std::atomic<bool> stop_reconnection_;
std::mutex reconnect_mutex_;
std::thread reconnecting_thread_;
VersionInformation urcontrol_version_;
double max_frequency_;
double target_frequency_;
ClientState client_state_;
constexpr static const double CB3_MAX_FREQUENCY = 125.0;
constexpr static const double URE_MAX_FREQUENCY = 500.0;
// Helper function to ensure that timestamp is present in the output recipe. The timestamp is needed to ensure that
// the robot is booted.
std::vector<std::string> ensureTimestampIsPresent(const std::vector<std::string>& output_recipe) const;
bool setupCommunication(const size_t max_num_tries = 0,
const std::chrono::milliseconds reconnection_time = std::chrono::seconds(10));
uint16_t negotiateProtocolVersion();
bool queryURControlVersion();
void setTargetFrequency();
bool setupOutputs(const uint16_t protocol_version);
bool setupInputs();
void disconnect();
/*!
* \brief Updates the output recipe to the given one and recreates all the objects which depend on it.
* It should only be called while setting up the communication.
*
* \param new_recipe the new output recipe to use
*/
void resetOutputRecipe(const std::vector<std::string> new_recipe);
/*!
* \brief Checks whether the robot is booted, this is done by looking at the timestamp from the robot controller, this
* will show the time in seconds since the controller was started. If the timestamp is below 40, we will read from
* the stream for approximately 1 second to ensure that the RTDE interface is up and running. This will ensure that we
* don't finalize setting up communication, before the controller is up and running. Else we could end up connecting
* to the RTDE interface, before a restart occurs during robot boot which would then destroy the connection
* established.
*
* \returns true if the robot is booted, false otherwise which will essentially trigger a reconnection.
*/
bool isRobotBooted();
bool sendStart();
bool sendPause();
/*!
* \brief Splits a variable_types string as reported from the robot into single variable type
* strings
*
* \param variable_types String as reported from the robot
*
* \returns A vector of variable variable_names
*/
std::vector<std::string> splitVariableTypes(const std::string& variable_types) const;
/*!
* \brief Reconnects to the RTDE interface and set the input and output recipes again.
*/
void reconnect();
void reconnectCallback();
};
} // namespace rtde_interface
} // namespace urcl
#endif // UR_CLIENT_LIBRARY_RTDE_CLIENT_H_INCLUDED