Skip to content

Commit 67e4b82

Browse files
urfeexurmahp
andauthored
Remove direct primary and secondary stream from UrDriver (#283)
And replace them with the PrimaryClient. --------- Co-authored-by: Mads Holm Peters <[email protected]>
1 parent 60a46ba commit 67e4b82

File tree

12 files changed

+143
-103
lines changed

12 files changed

+143
-103
lines changed

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -87,8 +87,8 @@ See [Architecture documentation](doc/architecture.rst)
8787

8888
Currently, this library doesn't support the primary interface very well, as the [Universal Robots
8989
ROS driver](https://github.com/UniversalRobots/Universal_Robots_ROS_Driver) was built mainly upon
90-
the RTDE interface. Therefore, there is also no `PrimaryClient` for directly accessing the primary
91-
interface. This may change in future, though.
90+
the RTDE interface. The `PrimaryClient` for directly accessing the primary
91+
interface doesn't support all features of the primary interface.
9292

9393
The `comm::URStream` class can be used to open a connection to the primary / secondary interface
9494
and send data to it. The [producer/consumer](#producer--consumer-architecture) pipeline structure

doc/architecture/ur_driver.rst

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ When creating an instance of the ``UrDriver`` class, the created object will con
1414
- a :ref:`ScriptCommandInterface <script_command_interface>`
1515
- a :ref:`ScriptSender <script_sender>`
1616
- a :ref:`TrajectoryPointInterface <trajectory_point_interface>`.
17-
- a rudimentary client to the robot's secondary interface
17+
- a rudimentary client to the robot's primary interface
1818
- a couple of helper functions
1919

2020
As this page is not meant to be a full-blown API documentation, not every public method will be
@@ -42,7 +42,7 @@ given to this function. Connection to the primary interface is dropped afterward
4242
``sendScript(const std::string& program)``
4343
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
4444

45-
This function sends given URScript code directly to the secondary interface. The
45+
This function sends given URScript code directly to the primary interface. The
4646
``sendRobotProgram()`` function is a special case that will send the script code given in the
4747
``RTDEClient`` constructor.
4848

doc/setup/robot_setup.rst

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ The robot needs to be prepared before it can be used with the client library.
3737
#. Go to the hamburger menu -> settings.
3838
#. Go to Security -> Services.
3939
#. Unlock the menu using the admin password.
40-
#. Enable the Dashboard Server, Primary Client Interface, Secondary Client Interface and Real-Time Data Exchange (RTDE) interfaces.
40+
#. Enable the Dashboard Server, Primary Client Interface and Real-Time Data Exchange (RTDE) interfaces.
4141
#. Lock the menu and press exit.
4242

4343
.. image:: ../images/initial_setup_images/services_polyscope5.png
@@ -52,7 +52,7 @@ The robot needs to be prepared before it can be used with the client library.
5252
#. Go to the hamburger menu -> settings.
5353
#. Go to Security -> Services.
5454
#. Unlock the menu using the admin password.
55-
#. Enable the Primary Client Interface, Secondary Client Interface and Real-Time Data Exchange (RTDE) interfaces.
55+
#. Enable the Primary Client Interface and Real-Time Data Exchange (RTDE) interfaces.
5656
#. Lock the menu and press exit.
5757

5858
.. image:: ../images/initial_setup_images/services_polyscopex.png

include/ur_client_library/primary/primary_client.h

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,14 +68,37 @@ class PrimaryClient
6868
void removePrimaryConsumer(std::shared_ptr<comm::IConsumer<PrimaryPackage>> primary_consumer);
6969
void start(const size_t max_connection_attempts = 0,
7070
const std::chrono::milliseconds reconnection_timeout = urcl::comm::TCPSocket::DEFAULT_RECONNECTION_TIME);
71+
void stop();
7172

7273
/*!
7374
* \brief Retrieves previously raised error codes from PrimaryClient. After calling this, recorded errors will be
7475
* deleted.
7576
*/
7677
std::deque<ErrorCode> getErrorCodes();
7778

79+
/*!
80+
* \brief Sends a custom script program to the robot.
81+
*
82+
* The given code must be valid according the UR Scripting Manual.
83+
*
84+
* \param program URScript code that shall be executed by the robot.
85+
*
86+
* \returns true on successful upload, false otherwise.
87+
*/
88+
bool sendScript(const std::string& program);
89+
90+
bool checkCalibration(const std::string& checksum);
91+
7892
private:
93+
/*!
94+
* \brief Reconnects the primary stream used to send program to the robot.
95+
*
96+
* Only for use in headless mode, as it replaces the use of the URCaps program.
97+
*
98+
* \returns true of on successful reconnection, false otherwise
99+
*/
100+
bool reconnectStream();
101+
79102
// The function is called whenever an error code message is received
80103
void errorMessageCallback(ErrorCode& code);
81104

include/ur_client_library/primary/primary_consumer.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,8 @@ class PrimaryConsumer : public AbstractPrimaryConsumer
9797
*/
9898
virtual bool consume(KinematicsInfo& pkg) override
9999
{
100+
URCL_LOG_DEBUG("%s", pkg.toString().c_str());
101+
kinematics_info_ = std::make_shared<KinematicsInfo>(pkg);
100102
return true;
101103
}
102104

@@ -162,8 +164,19 @@ class PrimaryConsumer : public AbstractPrimaryConsumer
162164
error_code_message_callback_ = callback_function;
163165
}
164166

167+
/*!
168+
* \brief Get the kinematics info
169+
*
170+
* \returns Shared pointer to the kinematics info
171+
*/
172+
std::shared_ptr<KinematicsInfo> getKinematicsInfo()
173+
{
174+
return kinematics_info_;
175+
}
176+
165177
private:
166178
std::function<void(ErrorCode&)> error_code_message_callback_;
179+
std::shared_ptr<KinematicsInfo> kinematics_info_;
167180
};
168181

169182
} // namespace primary_interface

include/ur_client_library/primary/robot_state/kinematics_info.h

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,14 +43,26 @@ namespace primary_interface
4343
class KinematicsInfo : public RobotState
4444
{
4545
public:
46-
KinematicsInfo() = delete;
46+
KinematicsInfo() : RobotState(RobotStateType::KINEMATICS_INFO)
47+
{
48+
}
4749
/*!
4850
* \brief Creates a new KinematicsInfo object.
4951
*
5052
* \param type The type of RobotState message received
5153
*/
52-
KinematicsInfo(const RobotStateType type) : RobotState(type)
54+
explicit KinematicsInfo(const RobotStateType type) : RobotState(type)
55+
{
56+
}
57+
58+
KinematicsInfo(const KinematicsInfo& other) : RobotState(RobotStateType::KINEMATICS_INFO)
5359
{
60+
checksum_ = other.checksum_;
61+
dh_theta_ = other.dh_theta_;
62+
dh_a_ = other.dh_a_;
63+
dh_d_ = other.dh_d_;
64+
dh_alpha_ = other.dh_alpha_;
65+
calibration_status_ = other.calibration_status_;
5466
}
5567
virtual ~KinematicsInfo() = default;
5668

include/ur_client_library/ur/calibration_checker.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,9 @@ namespace urcl
3939
* packages. These are then checked against the used kinematics to see if the correct calibration
4040
* is used.
4141
*/
42-
class CalibrationChecker : public comm::IConsumer<primary_interface::PrimaryPackage>
42+
class [[deprecated("Using the standalone CalibrationChecker consumer to compare the kinematics hash is deprecated. "
43+
"Please use the PrimaryClient instead.")]] CalibrationChecker
44+
: public comm::IConsumer<primary_interface::PrimaryPackage>
4345
{
4446
public:
4547
/*!

include/ur_client_library/ur/ur_driver.h

Lines changed: 5 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -868,18 +868,18 @@ class UrDriver
868868
*/
869869
void startPrimaryClientCommunication();
870870

871+
void stopPrimaryClientCommunication()
872+
{
873+
primary_client_->stop();
874+
}
875+
871876
void registerTrajectoryInterfaceDisconnectedCallback(std::function<void(const int)> fun)
872877
{
873878
trajectory_interface_->registerDisconnectionCallback(fun);
874879
}
875880

876881
static std::string readScriptFile(const std::string& filename);
877882

878-
void closeSecondaryStream()
879-
{
880-
secondary_stream_->close();
881-
}
882-
883883
bool isReverseInterfaceConnected() const
884884
{
885885
return reverse_interface_->isConnected();
@@ -893,15 +893,6 @@ class UrDriver
893893
private:
894894
void init(const UrDriverConfiguration& config);
895895

896-
/*!
897-
* \brief Reconnects the secondary stream used to send program to the robot.
898-
*
899-
* Only for use in headless mode, as it replaces the use of the URCaps program.
900-
*
901-
* \returns true of on successful reconnection, false otherwise
902-
*/
903-
bool reconnectSecondaryStream();
904-
905896
void initRTDE();
906897
void setupReverseInterface(const uint32_t reverse_port);
907898

@@ -912,8 +903,6 @@ class UrDriver
912903
std::unique_ptr<control::TrajectoryPointInterface> trajectory_interface_;
913904
std::unique_ptr<control::ScriptCommandInterface> script_command_interface_;
914905
std::unique_ptr<control::ScriptSender> script_sender_;
915-
std::unique_ptr<comm::URStream<primary_interface::PrimaryPackage>> primary_stream_;
916-
std::unique_ptr<comm::URStream<primary_interface::PrimaryPackage>> secondary_stream_;
917906

918907
size_t socket_connection_attempts_ = 0;
919908
std::chrono::milliseconds socket_reconnection_timeout_ = std::chrono::milliseconds(10000);

src/primary/primary_client.cpp

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,12 @@ void PrimaryClient::start(const size_t max_num_tries, const std::chrono::millise
6767
pipeline_->run();
6868
}
6969

70+
void PrimaryClient::stop()
71+
{
72+
pipeline_->stop();
73+
stream_.close();
74+
}
75+
7076
void PrimaryClient::addPrimaryConsumer(std::shared_ptr<comm::IConsumer<PrimaryPackage>> primary_consumer)
7177
{
7278
multi_consumer_->addConsumer(primary_consumer);
@@ -91,5 +97,68 @@ std::deque<ErrorCode> PrimaryClient::getErrorCodes()
9197
error_code_queue_.clear();
9298
return error_codes;
9399
}
100+
101+
bool PrimaryClient::sendScript(const std::string& program)
102+
{
103+
// urscripts (snippets) must end with a newline, or otherwise the controller's runtime will
104+
// not execute them. To avoid problems, we always just append a newline here, even if
105+
// there may already be one.
106+
auto program_with_newline = program + '\n';
107+
108+
size_t len = program_with_newline.size();
109+
const uint8_t* data = reinterpret_cast<const uint8_t*>(program_with_newline.c_str());
110+
size_t written;
111+
112+
const auto send_script_contents = [this, program_with_newline, data, len,
113+
&written](const std::string&& description) -> bool {
114+
if (stream_.write(data, len, written))
115+
{
116+
URCL_LOG_DEBUG("Sent program to robot:\n%s", program_with_newline.c_str());
117+
return true;
118+
}
119+
const std::string error_message = "Could not send program to robot: " + description;
120+
URCL_LOG_ERROR(error_message.c_str());
121+
return false;
122+
};
123+
124+
if (send_script_contents("initial attempt"))
125+
{
126+
return true;
127+
}
128+
129+
if (reconnectStream())
130+
{
131+
return send_script_contents("after reconnecting primary stream");
132+
}
133+
134+
return false;
135+
}
136+
137+
bool PrimaryClient::reconnectStream()
138+
{
139+
URCL_LOG_DEBUG("Closing primary stream...");
140+
stream_.close();
141+
if (stream_.connect())
142+
{
143+
URCL_LOG_DEBUG("Primary stream connected");
144+
return true;
145+
}
146+
URCL_LOG_ERROR("Failed to reconnect primary stream!");
147+
return false;
148+
}
149+
150+
bool PrimaryClient::checkCalibration(const std::string& checksum)
151+
{
152+
std::shared_ptr<primary_interface::KinematicsInfo> kin_info = consumer_->getKinematicsInfo();
153+
while (kin_info == nullptr)
154+
{
155+
std::this_thread::sleep_for(std::chrono::seconds(1));
156+
kin_info = consumer_->getKinematicsInfo();
157+
}
158+
URCL_LOG_DEBUG("Got calibration information from robot.");
159+
160+
return kin_info->toHash() == checksum;
161+
}
162+
94163
} // namespace primary_interface
95164
} // namespace urcl

0 commit comments

Comments
 (0)