Skip to content

Commit 1f26501

Browse files
committed
Improve primary client
Improved primary interface, this includes following changes: * Added message handlers for messages received through primary client * Changed primary pipeline and full driver example * Added datatype: vector6f_t and vector6uin8_t * Added parsing of vector6f_t * Changed timeout in producer * Added parsing of more messages from primary interface * Added calibration check in constructor of primary client * Added calibration checksum to urdriver constructor * Added test for primary client and primary parser * Added funtionality to set robot as simulated or real * Added wait in full driver example
1 parent 09adab9 commit 1f26501

File tree

63 files changed

+4972
-306
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

63 files changed

+4972
-306
lines changed

CMakeLists.txt

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,24 @@ add_library(urcl SHARED
2323
src/control/script_sender.cpp
2424
src/control/trajectory_point_interface.cpp
2525
src/control/script_command_interface.cpp
26+
src/primary/primary_client.cpp
2627
src/primary/primary_package.cpp
28+
src/primary/program_state_message.cpp
2729
src/primary/robot_message.cpp
2830
src/primary/robot_state.cpp
31+
src/primary/program_state_message/global_variables_update_message.cpp
32+
src/primary/program_state_message/global_variables_setup_message.cpp
33+
src/primary/robot_message/error_code_message.cpp
34+
src/primary/robot_message/runtime_exception_message.cpp
2935
src/primary/robot_message/version_message.cpp
36+
src/primary/robot_message/text_message.cpp
37+
src/primary/robot_message/key_message.cpp
3038
src/primary/robot_state/kinematics_info.cpp
39+
src/primary/robot_state/robot_mode_data.cpp
40+
src/primary/robot_state/joint_data.cpp
41+
src/primary/robot_state/cartesian_info.cpp
42+
src/primary/robot_state/force_mode_data.cpp
43+
src/primary/robot_state/additional_info.cpp
3144
src/rtde/control_package_pause.cpp
3245
src/rtde/control_package_setup_inputs.cpp
3346
src/rtde/control_package_setup_outputs.cpp

examples/full_driver.cpp

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -39,11 +39,14 @@ using namespace urcl;
3939

4040
// In a real-world example it would be better to get those values from command line parameters / a
4141
// better configuration system such as Boost.Program_options
42-
const std::string DEFAULT_ROBOT_IP = "192.168.56.101";
42+
// const std::string DEFAULT_ROBOT_IP = "192.168.56.101";
43+
const std::string DEFAULT_ROBOT_IP = "localhost";
4344
const std::string SCRIPT_FILE = "resources/external_control.urscript";
4445
const std::string OUTPUT_RECIPE = "examples/resources/rtde_output_recipe.txt";
4546
const std::string INPUT_RECIPE = "examples/resources/rtde_input_recipe.txt";
4647
const std::string CALIBRATION_CHECKSUM = "calib_12788084448423163542";
48+
const bool SIMULATED_ROBOT = true;
49+
bool g_program_running = false;
4750

4851
std::unique_ptr<UrDriver> g_my_driver;
4952
std::unique_ptr<DashboardClient> g_my_dashboard;
@@ -54,6 +57,7 @@ void handleRobotProgramState(bool program_running)
5457
{
5558
// Print the text in green so we see it better
5659
std::cout << "\033[1;32mProgram running: " << std::boolalpha << program_running << "\033[0m\n" << std::endl;
60+
g_program_running = program_running;
5761
}
5862

5963
int main(int argc, char* argv[])
@@ -109,11 +113,16 @@ int main(int argc, char* argv[])
109113
std::unique_ptr<ToolCommSetup> tool_comm_setup;
110114
const bool HEADLESS = true;
111115
g_my_driver.reset(new UrDriver(robot_ip, SCRIPT_FILE, OUTPUT_RECIPE, INPUT_RECIPE, &handleRobotProgramState, HEADLESS,
112-
std::move(tool_comm_setup), CALIBRATION_CHECKSUM));
116+
std::move(tool_comm_setup), CALIBRATION_CHECKSUM, SIMULATED_ROBOT));
113117

114118
// Once RTDE communication is started, we have to make sure to read from the interface buffer, as
115-
// otherwise we will get pipeline overflows. Therefor, do this directly before starting your main
119+
// otherwise we will get pipeline overflows. Therefore, do this directly before starting your main
116120
// loop.
121+
// Wait for the program to run on the robot
122+
while (!g_program_running)
123+
{
124+
std::this_thread::sleep_for(std::chrono::milliseconds(10));
125+
}
117126

118127
g_my_driver->startRTDECommunication();
119128

@@ -157,7 +166,7 @@ int main(int argc, char* argv[])
157166
URCL_LOG_ERROR("Could not send joint command. Is the robot in remote control?");
158167
return 1;
159168
}
160-
URCL_LOG_DEBUG("data_pkg:\n%s", data_pkg->toString());
169+
URCL_LOG_DEBUG("data_pkg:\n%s", data_pkg->toString().c_str());
161170
}
162171
else
163172
{

examples/primary_pipeline.cpp

Lines changed: 38 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -27,18 +27,19 @@
2727

2828
#include <ur_client_library/comm/pipeline.h>
2929
#include <ur_client_library/comm/producer.h>
30-
#include <ur_client_library/comm/shell_consumer.h>
3130
#include <ur_client_library/primary/primary_parser.h>
31+
#include <ur_client_library/primary/primary_client.h>
3232

3333
using namespace urcl;
3434

3535
// In a real-world example it would be better to get those values from command line parameters / a better configuration
3636
// system such as Boost.Program_options
37-
const std::string DEFAULT_ROBOT_IP = "192.168.56.101";
37+
// const std::string DEFAULT_ROBOT_IP = "192.168.56.101";
38+
const std::string DEFAULT_ROBOT_IP = "localhost";
39+
const std::string CALIBRATION_CHECKSUM = "calib_12788084448423163542";
3840

3941
int main(int argc, char* argv[])
4042
{
41-
// Set the loglevel to info get print out the DH parameters
4243
urcl::setLogLevel(urcl::LogLevel::INFO);
4344

4445
// Parse the ip arguments if given
@@ -48,40 +49,42 @@ int main(int argc, char* argv[])
4849
robot_ip = std::string(argv[1]);
4950
}
5051

51-
// Parse how many seconds to run
52-
int second_to_run = -1;
53-
if (argc > 2)
54-
{
55-
second_to_run = std::stoi(argv[2]);
56-
}
57-
58-
// First of all, we need a stream that connects to the robot
59-
comm::URStream<primary_interface::PrimaryPackage> primary_stream(robot_ip, urcl::primary_interface::UR_PRIMARY_PORT);
60-
61-
// This will parse the primary packages
62-
primary_interface::PrimaryParser parser;
63-
64-
// The producer needs both, the stream and the parser to fully work
65-
comm::URProducer<primary_interface::PrimaryPackage> prod(primary_stream, parser);
66-
prod.setupProducer();
52+
// First of all, we need to create a primary client that connects to the robot
53+
primary_interface::PrimaryClient primary_client(robot_ip, CALIBRATION_CHECKSUM);
6754

68-
// The shell consumer will print the package contents to the shell
69-
std::unique_ptr<comm::IConsumer<primary_interface::PrimaryPackage>> consumer;
70-
consumer.reset(new comm::ShellConsumer<primary_interface::PrimaryPackage>());
55+
// Give time to get the client to connect
56+
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
7157

72-
// The notifer will be called at some points during connection setup / loss. This isn't fully
73-
// implemented atm.
74-
comm::INotifier notifier;
75-
76-
// Now that we have all components, we can create and start the pipeline to run it all.
77-
comm::Pipeline<primary_interface::PrimaryPackage> pipeline(prod, consumer.get(), "Pipeline", notifier);
78-
pipeline.run();
79-
80-
// Package contents will be printed while not being interrupted
81-
// Note: Packages for which the parsing isn't implemented, will only get their raw bytes printed.
82-
do
58+
for (int i = 0; i < 10; ++i)
8359
{
84-
std::this_thread::sleep_for(std::chrono::seconds(second_to_run));
85-
} while (second_to_run < 0);
60+
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
61+
// Create script program to send through client
62+
std::stringstream cmd;
63+
cmd.imbue(std::locale::classic()); // Make sure, decimal divider is actually '.'
64+
cmd << "sec setup():" << std::endl
65+
<< " textmsg(\"Command through primary interface complete " << i++ << "\")" << std::endl
66+
<< "end";
67+
std::string script_code = cmd.str();
68+
auto program_with_newline = script_code + '\n';
69+
// Send script
70+
primary_client.sendScript(program_with_newline);
71+
72+
try
73+
{
74+
URCL_LOG_INFO("Cartesian Information:\n%s", primary_client.getCartesianInfo()->toString().c_str());
75+
URCL_LOG_INFO("Calibration Hash:\n%s", primary_client.getCalibrationChecker()->getData()->toHash().c_str());
76+
URCL_LOG_INFO("Build Date:\n%s", primary_client.getVersionMessage()->build_date_.c_str());
77+
std::cout << primary_client.getJointData()->toString() << std::endl;
78+
std::stringstream os;
79+
os << primary_client.getJointData()->q_actual_;
80+
URCL_LOG_INFO("Joint Angles:\n%s", os.str().c_str());
81+
// getGlobalVariablesSetupMessage() will throw an exception if a program on the robot has not been started
82+
URCL_LOG_INFO("Global Variables:\n%s", primary_client.getGlobalVariablesSetupMessage()->variable_names_.c_str());
83+
}
84+
catch (const UrException& e)
85+
{
86+
URCL_LOG_WARN(e.what());
87+
}
88+
}
8689
return 0;
8790
}

include/ur_client_library/comm/bin_parser.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -207,6 +207,19 @@ class BinParser
207207
}
208208
}
209209

210+
/*!
211+
* \brief Parses the next bytes as a vector of 6 floats.
212+
*
213+
* \param val Reference to write the parsed value to
214+
*/
215+
void parse(vector6f_t& val)
216+
{
217+
for (size_t i = 0; i < val.size(); ++i)
218+
{
219+
parse(val[i]);
220+
}
221+
}
222+
210223
/*!
211224
* \brief Parses the next bytes as a vector of 6 32 bit integers.
212225
*

include/ur_client_library/comm/pipeline.h

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -303,6 +303,8 @@ class Pipeline
303303
return;
304304

305305
URCL_LOG_DEBUG("Stopping pipeline! <%s>", name_.c_str());
306+
URCL_LOG_DEBUG("Producer thread joinable?! <%i>", pThread_.joinable());
307+
URCL_LOG_DEBUG("Consumer thread joinable?! <%i>", cThread_.joinable());
306308

307309
running_ = false;
308310

@@ -315,6 +317,7 @@ class Pipeline
315317
{
316318
cThread_.join();
317319
}
320+
URCL_LOG_DEBUG("Joined pipeline threads");
318321
notifier_.stopped(name_);
319322
}
320323

@@ -352,7 +355,7 @@ class Pipeline
352355

353356
void runProducer()
354357
{
355-
URCL_LOG_DEBUG("Starting up producer");
358+
URCL_LOG_DEBUG("Starting up producer <%s>", name_.c_str());
356359
std::ifstream realtime_file("/sys/kernel/realtime", std::ios::in);
357360
bool has_realtime;
358361
realtime_file >> has_realtime;
@@ -427,6 +430,7 @@ class Pipeline
427430
}
428431
URCL_LOG_DEBUG("Pipeline producer ended! <%s>", name_.c_str());
429432
notifier_.stopped(name_);
433+
URCL_LOG_DEBUG("Notifier producer ended! <%s>", name_.c_str());
430434
}
431435

432436
void runConsumer()
@@ -454,6 +458,7 @@ class Pipeline
454458
consumer_->stopConsumer();
455459
URCL_LOG_DEBUG("Pipeline consumer ended! <%s>", name_.c_str());
456460
notifier_.stopped(name_);
461+
URCL_LOG_DEBUG("Notifier consumer ended! <%s>", name_.c_str());
457462
}
458463
};
459464
} // namespace comm

include/ur_client_library/comm/producer.h

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ class URProducer : public IProducer<T>
4242
private:
4343
URStream<T>& stream_;
4444
Parser<T>& parser_;
45-
std::chrono::seconds timeout_;
45+
std::chrono::milliseconds timeout_;
4646

4747
bool running_;
4848

@@ -57,6 +57,8 @@ class URProducer : public IProducer<T>
5757
{
5858
}
5959

60+
virtual ~URProducer() = default;
61+
6062
/*!
6163
* \brief Triggers the stream to connect to the robot.
6264
*/
@@ -83,6 +85,7 @@ class URProducer : public IProducer<T>
8385
*/
8486
void stopProducer() override
8587
{
88+
URCL_LOG_DEBUG("Stopping producer");
8689
running_ = false;
8790
}
8891

@@ -105,24 +108,24 @@ class URProducer : public IProducer<T>
105108
// 4KB should be enough to hold any packet received from UR
106109
uint8_t buf[4096];
107110
size_t read = 0;
108-
// expoential backoff reconnects
111+
// exponential backoff reconnects
109112
while (true)
110113
{
114+
if (!running_)
115+
return true;
116+
111117
if (stream_.read(buf, sizeof(buf), read))
112118
{
113119
// reset sleep amount
114-
timeout_ = std::chrono::seconds(1);
120+
timeout_ = std::chrono::milliseconds(100);
115121
BinParser bp(buf, read);
116122
return parser_.parse(bp, products);
117123
}
118124

119-
if (!running_)
120-
return true;
121-
122125
if (stream_.closed())
123126
return false;
124127

125-
URCL_LOG_WARN("Failed to read from stream, reconnecting in %ld seconds...", timeout_.count());
128+
URCL_LOG_WARN("Failed to read from stream, reconnecting in %ld milliseconds...", timeout_.count());
126129
std::this_thread::sleep_for(timeout_);
127130

128131
if (stream_.connect())

include/ur_client_library/primary/abstract_primary_consumer.h

Lines changed: 27 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,13 +26,24 @@
2626
*/
2727
//----------------------------------------------------------------------
2828

29-
#ifndef UR_ROBOT_DRIVER_ABSTRACT_PRIMARY_CONSUMER_H_INCLUDED
30-
#define UR_ROBOT_DRIVER_ABSTRACT_PRIMARY_CONSUMER_H_INCLUDED
29+
#ifndef UR_CLIENT_LIBRARY_ABSTRACT_PRIMARY_CONSUMER_H_INCLUDED
30+
#define UR_CLIENT_LIBRARY_ABSTRACT_PRIMARY_CONSUMER_H_INCLUDED
3131

3232
#include "ur_client_library/log.h"
3333
#include "ur_client_library/comm/pipeline.h"
34+
#include "ur_client_library/primary/robot_message/error_code_message.h"
35+
#include "ur_client_library/primary/robot_message/key_message.h"
36+
#include "ur_client_library/primary/robot_message/runtime_exception_message.h"
37+
#include "ur_client_library/primary/robot_message/text_message.h"
3438
#include "ur_client_library/primary/robot_message/version_message.h"
39+
#include "ur_client_library/primary/robot_state/robot_mode_data.h"
40+
#include "ur_client_library/primary/robot_state/joint_data.h"
41+
#include "ur_client_library/primary/robot_state/cartesian_info.h"
3542
#include "ur_client_library/primary/robot_state/kinematics_info.h"
43+
#include "ur_client_library/primary/robot_state/force_mode_data.h"
44+
#include "ur_client_library/primary/robot_state/additional_info.h"
45+
#include "ur_client_library/primary/program_state_message/global_variables_update_message.h"
46+
#include "ur_client_library/primary/program_state_message/global_variables_setup_message.h"
3647

3748
namespace urcl
3849
{
@@ -51,7 +62,7 @@ class AbstractPrimaryConsumer : public comm::IConsumer<PrimaryPackage>
5162
virtual ~AbstractPrimaryConsumer() = default;
5263

5364
/*!
54-
* \brief This consume method is usally being called by the Pipeline structure. We don't
65+
* \brief This consume method is usually being called by the Pipeline structure. We don't
5566
* necessarily need to know the specific package type here, as the packages themselves will take
5667
* care to be consumed with the correct function (visitor pattern).
5768
*
@@ -71,13 +82,25 @@ class AbstractPrimaryConsumer : public comm::IConsumer<PrimaryPackage>
7182
// To be implemented in specific consumers
7283
virtual bool consume(RobotMessage& pkg) = 0;
7384
virtual bool consume(RobotState& pkg) = 0;
85+
virtual bool consume(ErrorCodeMessage& pkg) = 0;
86+
virtual bool consume(KeyMessage& pkg) = 0;
87+
virtual bool consume(RuntimeExceptionMessage& pkg) = 0;
88+
virtual bool consume(TextMessage& pkg) = 0;
7489
virtual bool consume(VersionMessage& pkg) = 0;
90+
virtual bool consume(RobotModeData& pkg) = 0;
91+
virtual bool consume(JointData& pkg) = 0;
92+
virtual bool consume(CartesianInfo& pkg) = 0;
7593
virtual bool consume(KinematicsInfo& pkg) = 0;
94+
virtual bool consume(ForceModeData& pkg) = 0;
95+
virtual bool consume(AdditionalInfo& pkg) = 0;
96+
virtual bool consume(ProgramStateMessage& pkg) = 0;
97+
virtual bool consume(GlobalVariablesUpdateMessage& pkg) = 0;
98+
virtual bool consume(GlobalVariablesSetupMessage& pkg) = 0;
7699

77100
private:
78101
/* data */
79102
};
80103
} // namespace primary_interface
81104
} // namespace urcl
82105

83-
#endif // ifndef UR_ROBOT_DRIVER_ABSTRACT_PRIMARY_CONSUMER_H_INCLUDED
106+
#endif // ifndef UR_CLIENT_LIBRARY_ABSTRACT_PRIMARY_CONSUMER_H_INCLUDED

0 commit comments

Comments
 (0)