Skip to content

Commit 01cf607

Browse files
authored
Add getKinematicsInfo accessor to PrimaryClient (UniversalRobots#496)
Adds a `getKinematicsInfo()` accessor on `PrimaryClient` that forwards to the internal `PrimaryConsumer`'s existing accessor. This mirrors the pattern of `getConfigurationData()` Also adds the missing mutex around `kinematics_info_` in `PrimaryConsumer`, matching the synchronization pattern already uses in every other captures packet member (`robot_mode_`, `configuration_data_`, `version_information_`, etc). Without it the new public accessor would expose a data race between the pipeline thread that writes `kinematics_info_` and the caller thread that reads it.
1 parent 8f48a06 commit 01cf607

3 files changed

Lines changed: 35 additions & 0 deletions

File tree

include/ur_client_library/primary/primary_client.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -258,6 +258,20 @@ class PrimaryClient
258258
return consumer_->getConfigurationData();
259259
}
260260

261+
/*!
262+
* \brief Get the latest kinematics info.
263+
*
264+
* The kinematics info contains the controller's calibrated DH parameters: the nominal model
265+
* combined with the per-arm calibration deltas, plus the calibration checksum/status. It
266+
* will be updated in the background. This will always show the latest received kinematics
267+
* info independent of the time that has passed since receiving it. If no kinematics info
268+
* has been received yet, this will return a nullptr.
269+
*/
270+
std::shared_ptr<KinematicsInfo> getKinematicsInfo()
271+
{
272+
return consumer_->getKinematicsInfo();
273+
}
274+
261275
/*!
262276
* \brief Get the Robot type
263277
*

include/ur_client_library/primary/primary_consumer.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,7 @@ class PrimaryConsumer : public AbstractPrimaryConsumer
107107
virtual bool consume(KinematicsInfo& pkg) override
108108
{
109109
URCL_LOG_DEBUG("%s", pkg.toString().c_str());
110+
std::scoped_lock lock(kinematics_info_mutex_);
110111
kinematics_info_ = std::make_shared<KinematicsInfo>(pkg);
111112
return true;
112113
}
@@ -203,6 +204,7 @@ class PrimaryConsumer : public AbstractPrimaryConsumer
203204
*/
204205
std::shared_ptr<KinematicsInfo> getKinematicsInfo()
205206
{
207+
std::scoped_lock lock(kinematics_info_mutex_);
206208
return kinematics_info_;
207209
}
208210

@@ -259,6 +261,7 @@ class PrimaryConsumer : public AbstractPrimaryConsumer
259261
private:
260262
std::function<void(ErrorCode&)> error_code_message_callback_;
261263
std::shared_ptr<KinematicsInfo> kinematics_info_;
264+
std::mutex kinematics_info_mutex_;
262265
std::mutex robot_mode_mutex_;
263266
std::shared_ptr<RobotModeData> robot_mode_;
264267
std::mutex version_information_mutex_;

tests/test_primary_client.cpp

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -268,6 +268,24 @@ TEST_F(PrimaryClientTest, test_configuration_data)
268268
EXPECT_NE(client_->getRobotType(), RobotType::UNDEFINED);
269269
}
270270

271+
TEST_F(PrimaryClientTest, test_kinematics_info)
272+
{
273+
EXPECT_NO_THROW(client_->start());
274+
275+
// Once we connect to the primary client we should receive kinematics info
276+
auto start_time = std::chrono::system_clock::now();
277+
const auto timeout = std::chrono::seconds(1);
278+
auto kinematics_info = client_->getKinematicsInfo();
279+
while (kinematics_info == nullptr && std::chrono::system_clock::now() - start_time < timeout)
280+
{
281+
std::this_thread::sleep_for(std::chrono::milliseconds(100));
282+
kinematics_info = client_->getKinematicsInfo();
283+
}
284+
285+
// We should have received a kinematics info package
286+
EXPECT_NE(kinematics_info, nullptr);
287+
}
288+
271289
TEST_F(PrimaryClientTest, test_get_robot_series)
272290
{
273291
EXPECT_NO_THROW(client_->start());

0 commit comments

Comments
 (0)