Skip to content

Commit 892d28b

Browse files
committed
Add power_on, power_off and brake_release to primary client
1 parent 1543e72 commit 892d28b

File tree

7 files changed

+186
-1
lines changed

7 files changed

+186
-1
lines changed

include/ur_client_library/helpers.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@
2929
#ifndef UR_CLIENT_LIBRARY_HELPERS_H_INCLUDED
3030
#define UR_CLIENT_LIBRARY_HELPERS_H_INCLUDED
3131

32+
#include <chrono>
33+
#include <functional>
3234
#ifdef _WIN32
3335

3436
# define NOMINMAX
@@ -63,5 +65,7 @@ static inline int sched_get_priority_max(int policy)
6365
namespace urcl
6466
{
6567
bool setFiFoScheduling(pthread_t& thread, const int priority);
66-
}
68+
bool waitFor(std::function<bool()> condition, const std::chrono::milliseconds timeout,
69+
const std::chrono::milliseconds check_interval = std::chrono::milliseconds(50));
70+
} // namespace urcl
6771
#endif // ifndef UR_CLIENT_LIBRARY_HELPERS_H_INCLUDED

include/ur_client_library/primary/abstract_primary_consumer.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
#include "ur_client_library/primary/robot_message/version_message.h"
3535
#include "ur_client_library/primary/robot_message/error_code_message.h"
3636
#include "ur_client_library/primary/robot_state/kinematics_info.h"
37+
#include "ur_client_library/primary/robot_state/robot_mode_data.h"
3738

3839
namespace urcl
3940
{
@@ -75,6 +76,7 @@ class AbstractPrimaryConsumer : public comm::IConsumer<PrimaryPackage>
7576
virtual bool consume(VersionMessage& pkg) = 0;
7677
virtual bool consume(KinematicsInfo& pkg) = 0;
7778
virtual bool consume(ErrorCodeMessage& pkg) = 0;
79+
virtual bool consume(RobotModeData& pkg) = 0;
7880

7981
private:
8082
/* data */

include/ur_client_library/primary/primary_client.h

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
#ifndef UR_CLIENT_LIBRARY_PRIMARY_CLIENT_H_INCLUDED
3232
#define UR_CLIENT_LIBRARY_PRIMARY_CLIENT_H_INCLUDED
3333

34+
#include <chrono>
3435
#include <memory>
3536
#include <deque>
3637

@@ -89,6 +90,58 @@ class PrimaryClient
8990

9091
bool checkCalibration(const std::string& checksum);
9192

93+
/*!
94+
* \brief Commands the robot to power on.
95+
*
96+
* \param validate If true, the function will block until the robot is powered on or the timeout
97+
* passed by.
98+
* \param timeout The maximum time to wait for the robot to confirm the power on command.
99+
*
100+
* \returns true on successful power on, false otherwise.
101+
*/
102+
bool commandPowerOn(const bool validate = true,
103+
const std::chrono::milliseconds timeout = std::chrono::milliseconds(5000));
104+
105+
/*!
106+
* \brief Commands the robot to power off.
107+
*
108+
* \param validate If true, the function will block until the robot is powered off or the timeout
109+
* passed by.
110+
* \param timeout The maximum time to wait for the robot to confirm the power off command.
111+
*
112+
* \returns true on successful power off, false otherwise.
113+
*/
114+
bool commandPowerOff(const bool validate = true,
115+
const std::chrono::milliseconds timeout = std::chrono::milliseconds(5000));
116+
117+
/*!
118+
* \brief Commands the robot to release the brakes
119+
*
120+
* \param validate If true, the function will block until the robot is running or the timeout
121+
* passed by.
122+
* \param timeout The maximum time to wait for the robot to confirm it is running.
123+
*
124+
* \returns true on successful brake release, false otherwise.
125+
*/
126+
bool commandBrakeRelease(const bool validate = true,
127+
const std::chrono::milliseconds timeout = std::chrono::milliseconds(5000));
128+
129+
/*!
130+
* \brief Get the latest robot mode.
131+
*
132+
* The robot mode will be updated in the background. This will always show the latest received
133+
* robot mode independent of the time that has passed since receiving it.
134+
*/
135+
RobotMode getRobotMode()
136+
{
137+
std::shared_ptr<RobotModeData> robot_mode_data = consumer_->getRobotModeData();
138+
if (robot_mode_data == nullptr)
139+
{
140+
return RobotMode::UNKNOWN;
141+
}
142+
return static_cast<RobotMode>(consumer_->getRobotModeData()->robot_mode_);
143+
}
144+
92145
private:
93146
/*!
94147
* \brief Reconnects the primary stream used to send program to the robot.
@@ -99,6 +152,9 @@ class PrimaryClient
99152
*/
100153
bool reconnectStream();
101154

155+
bool waitFor(std::function<bool()> condition, const std::chrono::milliseconds timeout,
156+
const std::chrono::milliseconds check_interval = std::chrono::milliseconds(50));
157+
102158
// The function is called whenever an error code message is received
103159
void errorMessageCallback(ErrorCode& code);
104160

include/ur_client_library/primary/primary_consumer.h

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@
2929
#define UR_CLIENT_LIBRARY_PRIMARY_CONSUMER_H_INCLUDED
3030

3131
#include "ur_client_library/primary/abstract_primary_consumer.h"
32+
#include "ur_client_library/primary/robot_state/robot_mode_data.h"
33+
#include "ur_client_library/ur/datatypes.h"
3234

3335
#include <functional>
3436
#include <mutex>
@@ -153,6 +155,14 @@ class PrimaryConsumer : public AbstractPrimaryConsumer
153155
return true;
154156
}
155157

158+
virtual bool consume(RobotModeData& pkg) override
159+
{
160+
URCL_LOG_DEBUG("Robot mode is now %s", robotModeString(static_cast<RobotMode>(pkg.robot_mode_)).c_str());
161+
std::scoped_lock lock(robot_mode_mutex_);
162+
robot_mode_ = std::make_shared<RobotModeData>(pkg);
163+
return true;
164+
}
165+
156166
/*!
157167
* \brief Set callback function which will be triggered whenever error code messages are received
158168
*
@@ -174,9 +184,23 @@ class PrimaryConsumer : public AbstractPrimaryConsumer
174184
return kinematics_info_;
175185
}
176186

187+
/*!
188+
* \brief Get the latest robot mode.
189+
*
190+
* The robot mode will be updated in the background. This will always show the latest received
191+
* robot mode independent of the time that has passed since receiving it.
192+
*/
193+
std::shared_ptr<RobotModeData> getRobotModeData()
194+
{
195+
std::scoped_lock lock(robot_mode_mutex_);
196+
return robot_mode_;
197+
}
198+
177199
private:
178200
std::function<void(ErrorCode&)> error_code_message_callback_;
179201
std::shared_ptr<KinematicsInfo> kinematics_info_;
202+
std::mutex robot_mode_mutex_;
203+
std::shared_ptr<RobotModeData> robot_mode_;
180204
};
181205

182206
} // namespace primary_interface

src/helpers.cpp

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
#include <cstring>
3333
#include <fstream>
3434
#include <iostream>
35+
#include <thread>
3536

3637
// clang-format off
3738
// We want to keep the URL in one line to avoid formatting issues. This will make it easier to
@@ -99,4 +100,20 @@ bool setFiFoScheduling(pthread_t& thread, const int priority)
99100
return true;
100101
#endif
101102
}
103+
104+
bool waitFor(std::function<bool()> condition, const std::chrono::milliseconds timeout,
105+
const std::chrono::milliseconds check_interval)
106+
{
107+
auto start_time = std::chrono::system_clock::now();
108+
while (std::chrono::system_clock::now() - start_time < timeout)
109+
{
110+
if (condition())
111+
{
112+
return true;
113+
}
114+
URCL_LOG_DEBUG("Waiting for condition to be met...");
115+
std::this_thread::sleep_for(check_interval);
116+
}
117+
return false;
118+
}
102119
} // namespace urcl

src/primary/primary_client.cpp

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,5 +160,60 @@ bool PrimaryClient::checkCalibration(const std::string& checksum)
160160
return kin_info->toHash() == checksum;
161161
}
162162

163+
bool PrimaryClient::commandPowerOn(const bool validate, const std::chrono::milliseconds timeout)
164+
{
165+
if (!sendScript("power on"))
166+
{
167+
return false;
168+
}
169+
170+
if (validate)
171+
{
172+
return waitFor([this]() { return getRobotMode() == RobotMode::IDLE; }, timeout);
173+
}
174+
return true;
175+
}
176+
177+
bool PrimaryClient::commandPowerOff(const bool validate, const std::chrono::milliseconds timeout)
178+
{
179+
if (!sendScript("power off"))
180+
{
181+
return false;
182+
}
183+
if (validate)
184+
{
185+
return waitFor([this]() { return getRobotMode() == RobotMode::POWER_OFF; }, timeout);
186+
}
187+
return true;
188+
}
189+
190+
bool PrimaryClient::commandBrakeRelease(const bool validate, const std::chrono::milliseconds timeout)
191+
{
192+
if (!sendScript("set robotmode run"))
193+
{
194+
return false;
195+
}
196+
if (validate)
197+
{
198+
return waitFor([this]() { return getRobotMode() == RobotMode::RUNNING; }, timeout);
199+
}
200+
return true;
201+
}
202+
203+
bool PrimaryClient::waitFor(std::function<bool()> condition, const std::chrono::milliseconds timeout,
204+
const std::chrono::milliseconds check_interval)
205+
{
206+
auto start_time = std::chrono::system_clock::now();
207+
while (std::chrono::system_clock::now() - start_time < timeout)
208+
{
209+
if (condition())
210+
{
211+
return true;
212+
}
213+
URCL_LOG_DEBUG("Waiting for condition to be met...");
214+
std::this_thread::sleep_for(check_interval);
215+
}
216+
return false;
217+
}
163218
} // namespace primary_interface
164219
} // namespace urcl

tests/test_primary_client.cpp

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,10 @@
3232

3333
#include <ur_client_library/primary/primary_client.h>
3434
#include <ur_client_library/ur/calibration_checker.h>
35+
#include <chrono>
3536
#include <memory>
37+
#include <thread>
38+
#include "ur_client_library/helpers.h"
3639

3740
using namespace urcl;
3841

@@ -77,9 +80,33 @@ TEST_F(PrimaryClientTest, add_and_remove_consumer)
7780
client_->removePrimaryConsumer(calibration_consumer);
7881
}
7982

83+
TEST_F(PrimaryClientTest, test_power_cycle_commands)
84+
{
85+
EXPECT_NO_THROW(client_->start());
86+
EXPECT_TRUE(client_->commandPowerOff());
87+
EXPECT_TRUE(client_->commandPowerOn());
88+
EXPECT_TRUE(client_->commandBrakeRelease());
89+
EXPECT_TRUE(client_->commandPowerOff());
90+
EXPECT_TRUE(client_->commandBrakeRelease());
91+
EXPECT_TRUE(client_->commandPowerOff());
92+
93+
// provoke a timeout
94+
EXPECT_FALSE(client_->commandBrakeRelease(true, std::chrono::milliseconds(1)));
95+
96+
auto timeout = std::chrono::milliseconds(1000);
97+
waitFor([this]() { return client_->getRobotMode() == RobotMode::RUNNING; }, timeout);
98+
EXPECT_EQ(client_->getRobotMode(), RobotMode::RUNNING);
99+
100+
EXPECT_TRUE(client_->commandPowerOff(false));
101+
waitFor([this]() { return client_->getRobotMode() == RobotMode::POWER_OFF; }, timeout);
102+
103+
EXPECT_EQ(client_->getRobotMode(), RobotMode::POWER_OFF);
104+
}
105+
80106
int main(int argc, char* argv[])
81107
{
82108
::testing::InitGoogleTest(&argc, argv);
109+
urcl::setLogLevel(urcl::LogLevel::DEBUG);
83110

84111
return RUN_ALL_TESTS();
85112
}

0 commit comments

Comments
 (0)