test_script_command_interface.cpp
Go to the documentation of this file.
1 // -- BEGIN LICENSE BLOCK ----------------------------------------------
2 // Copyright 2022 Universal Robots A/S
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions are met:
6 //
7 // * Redistributions of source code must retain the above copyright
8 // notice, this list of conditions and the following disclaimer.
9 //
10 // * Redistributions in binary form must reproduce the above copyright
11 // notice, this list of conditions and the following disclaimer in the
12 // documentation and/or other materials provided with the distribution.
13 //
14 // * Neither the name of the {copyright_holder} nor the names of its
15 // contributors may be used to endorse or promote products derived from
16 // this software without specific prior written permission.
17 //
18 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
22 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28 // POSSIBILITY OF SUCH DAMAGE.
29 // -- END LICENSE BLOCK ------------------------------------------------
30 
31 #include <gtest/gtest.h>
32 #include <iterator>
33 #include <numeric>
34 
37 
38 using namespace urcl;
39 
40 class ScriptCommandInterfaceTest : public ::testing::Test
41 {
42 protected:
43  class Client : public comm::TCPSocket
44  {
45  public:
46  Client(const int& port)
47  {
48  std::string host = "127.0.0.1";
49  TCPSocket::setup(host, port);
50  timeval tv;
51  tv.tv_sec = 1;
52  tv.tv_usec = 0;
53  TCPSocket::setReceiveTimeout(tv);
54  }
55 
56  void send(const int32_t& result)
57  {
58  uint8_t buffer[sizeof(int32_t)];
59  int32_t val = htobe32(result);
60  std::memcpy(buffer, &val, sizeof(int32_t));
61  size_t written = 0;
62  TCPSocket::write(buffer, sizeof(buffer), written);
63  }
64 
65  void readMessage(int32_t& command, std::vector<int32_t>& message)
66  {
67  // Max message length is 26
68  uint8_t buf[sizeof(int32_t) * 26];
69  uint8_t* b_pos = buf;
70  size_t read = 0;
71  size_t remainder = sizeof(int32_t) * 26;
72  while (remainder > 0)
73  {
74  if (!TCPSocket::read(b_pos, remainder, read))
75  {
76  std::cout << "Failed to read from socket, this should not happen during a test!" << std::endl;
77  break;
78  }
79  b_pos += read;
80  remainder -= read;
81  }
82 
83  // Reset buffer pos for parsing
84  b_pos = buf;
85  uint8_t* b_end = b_pos + read;
86 
87  // Decode command signal
88  int32_t val;
89  std::memcpy(&val, b_pos, sizeof(int32_t));
90  command = be32toh(val);
91  b_pos += sizeof(int32_t);
92 
93  // Decode remainder of message
94  while (b_pos < b_end)
95  {
96  std::memcpy(&val, b_pos, sizeof(int32_t));
97  message.push_back(be32toh(val));
98  b_pos += sizeof(int32_t);
99  }
100  }
101 
102  protected:
103  virtual bool open(int socket_fd, struct sockaddr* address, size_t address_len)
104  {
105  return ::connect(socket_fd, address, address_len) == 0;
106  }
107  };
108 
109  void SetUp()
110  {
111  script_command_interface_.reset(new control::ScriptCommandInterface(50004));
112  client_.reset(new Client(50004));
113  }
114 
115  void TearDown()
116  {
117  if (script_command_interface_->clientConnected() == true)
118  {
119  client_->close();
120  waitForClientConnection(false);
121  }
122  }
123 
124  bool waitForClientConnection(bool client_connected = true,
125  std::chrono::duration<double> timeout = std::chrono::milliseconds(1000))
126  {
127  const std::chrono::duration<double> wait_period = std::chrono::milliseconds(50);
128  std::chrono::duration<double> time_done(0);
129  while (time_done < timeout)
130  {
131  if (script_command_interface_->clientConnected() == client_connected)
132  {
133  return true;
134  }
135  std::this_thread::sleep_for(wait_period);
136  time_done += wait_period;
137  }
138  return false;
139  }
140 
141  bool waitToolContactResult(control::ToolContactResult result, int milliseconds = 1000)
142  {
143  std::unique_lock<std::mutex> lk(tool_contact_result_mutex_);
144  if (tool_contact_result_.wait_for(lk, std::chrono::milliseconds(milliseconds)) == std::cv_status::no_timeout ||
145  received_result_ == result)
146  {
147  if (received_result_ == result)
148  {
149  return true;
150  }
151  }
152  return false;
153  }
154 
155  std::unique_ptr<control::ScriptCommandInterface> script_command_interface_;
156  std::unique_ptr<Client> client_;
158 
159 public:
161  {
162  std::lock_guard<std::mutex> lk(tool_contact_result_mutex_);
163  tool_contact_result_.notify_one();
164  received_result_ = result;
165  }
166 
167 private:
168  std::condition_variable tool_contact_result_;
170 };
171 
172 TEST_F(ScriptCommandInterfaceTest, test_zero_ft_sensor)
173 {
174  // Wait for the client to connect to the server
175  waitForClientConnection();
176 
177  script_command_interface_->zeroFTSensor();
178  int32_t command;
179  std::vector<int32_t> message;
180  client_->readMessage(command, message);
181 
182  // 0 is zero ft sensor
183  int32_t expected_command = 0;
184  EXPECT_EQ(command, expected_command);
185 
186  // The rest of the message should be zero
187  int32_t message_sum = std::accumulate(std::begin(message), std::end(message), 0);
188  int32_t expected_message_sum = 0;
189  EXPECT_EQ(message_sum, expected_message_sum);
190 }
191 
193 {
194  // Wait for the client to connect to the server
195  waitForClientConnection();
196 
197  double mass = 1.0;
198  vector3d_t cog = { 0.2, 0.3, 0.1 };
199  script_command_interface_->setPayload(mass, &cog);
200  int32_t command;
201  std::vector<int32_t> message;
202  client_->readMessage(command, message);
203 
204  // 1 is set payload
205  int32_t expected_command = 1;
206  EXPECT_EQ(command, expected_command);
207 
208  // Test mass
209  double received_mass = (double)message[0] / script_command_interface_->MULT_JOINTSTATE;
210  EXPECT_EQ(received_mass, mass);
211 
212  // Test cog
213  vector3d_t received_cog;
214  for (unsigned int i = 0; i < cog.size(); ++i)
215  {
216  received_cog[i] = (double)message[i + 1] / script_command_interface_->MULT_JOINTSTATE;
217  EXPECT_EQ(received_cog[i], cog[i]);
218  }
219 
220  // The rest of the message should be zero
221  int32_t message_sum = std::accumulate(std::begin(message) + 4, std::end(message), 0);
222  int32_t expected_message_sum = 0;
223  EXPECT_EQ(message_sum, expected_message_sum);
224 }
225 
226 TEST_F(ScriptCommandInterfaceTest, test_set_tool_voltage)
227 {
228  // Wait for the client to connect to the server
229  waitForClientConnection();
230 
231  ToolVoltage tool_voltage = ToolVoltage::_12V;
232  script_command_interface_->setToolVoltage(tool_voltage);
233  int32_t command;
234  std::vector<int32_t> message;
235  client_->readMessage(command, message);
236 
237  // 2 is set tool voltage
238  int32_t expected_command = 2;
239  EXPECT_EQ(command, expected_command);
240 
241  // Test tool voltage
242  int received_tool_voltage = message[0] / script_command_interface_->MULT_JOINTSTATE;
243  EXPECT_EQ(received_tool_voltage, toUnderlying(tool_voltage));
244 
245  // The rest of the message should be zero
246  int32_t message_sum = std::accumulate(std::begin(message) + 1, std::end(message), 0);
247  int32_t expected_message_sum = 0;
248  EXPECT_EQ(message_sum, expected_message_sum);
249 }
250 
252 {
253  // Wait for the client to connect to the server
254  waitForClientConnection();
255 
256  urcl::vector6d_t task_frame = { 0.1, 0, 0, 0, 0, 0.785 };
257  urcl::vector6uint32_t selection_vector = { 0, 0, 1, 0, 0, 0 };
258  urcl::vector6d_t wrench = { 20, 0, 40, 0, 0, 0 };
259  int32_t force_mode_type = 2;
260  urcl::vector6d_t limits = { 0.1, 0.1, 0.1, 0.785, 0.785, 1.57 };
261  script_command_interface_->startForceMode(&task_frame, &selection_vector, &wrench, force_mode_type, &limits);
262 
263  int32_t command;
264  std::vector<int32_t> message;
265  client_->readMessage(command, message);
266 
267  // 3 is start force mode
268  int32_t expected_command = 3;
269  EXPECT_EQ(command, expected_command);
270 
271  // Test task frame
272  vector6d_t received_task_frame;
273  for (unsigned int i = 0; i < task_frame.size(); ++i)
274  {
275  received_task_frame[i] = (double)message[i] / script_command_interface_->MULT_JOINTSTATE;
276  EXPECT_EQ(received_task_frame[i], task_frame[i]);
277  }
278 
279  // Test selection vector
280  vector6uint32_t received_selection_vector;
281  for (unsigned int i = 0; i < selection_vector.size(); ++i)
282  {
283  received_selection_vector[i] = message[i + 6] / script_command_interface_->MULT_JOINTSTATE;
284  EXPECT_EQ(received_selection_vector[i], selection_vector[i]);
285  }
286 
287  // Test wrench
288  vector6d_t received_wrench;
289  for (unsigned int i = 0; i < wrench.size(); ++i)
290  {
291  received_wrench[i] = (double)message[i + 12] / script_command_interface_->MULT_JOINTSTATE;
292  EXPECT_EQ(received_wrench[i], wrench[i]);
293  }
294 
295  // Test force mode type
296  int32_t received_force_mode_type = message[18] / script_command_interface_->MULT_JOINTSTATE;
297  EXPECT_EQ(received_force_mode_type, force_mode_type);
298 
299  // Test limits
300  vector6d_t received_limits;
301  for (unsigned int i = 0; i < wrench.size(); ++i)
302  {
303  received_limits[i] = (double)message[i + 19] / script_command_interface_->MULT_JOINTSTATE;
304  EXPECT_EQ(received_limits[i], limits[i]);
305  }
306 
307  // The rest of the message should be zero
308  int32_t message_sum = std::accumulate(std::begin(message) + 25, std::end(message), 0);
309  int32_t expected_message_sum = 0;
310  EXPECT_EQ(message_sum, expected_message_sum);
311 
312  // End force mode
313  script_command_interface_->endForceMode();
314  message.clear();
315  client_->readMessage(command, message);
316 
317  // 4 is end force mode
318  expected_command = 4;
319  EXPECT_EQ(command, expected_command);
320 
321  // The rest of the message should be zero
322  message_sum = std::accumulate(std::begin(message), std::end(message), 0);
323  EXPECT_EQ(message_sum, expected_message_sum);
324 }
325 
327 {
328  // Wait for the client to connect to the server
329  waitForClientConnection();
330 
331  script_command_interface_->startToolContact();
332 
333  int32_t command;
334  std::vector<int32_t> message;
335  client_->readMessage(command, message);
336 
337  // 5 is start tool contact
338  int32_t expected_command = 5;
339  EXPECT_EQ(command, expected_command);
340 
341  // The rest of the message should be zero
342  int32_t message_sum = std::accumulate(std::begin(message) + 25, std::end(message), 0);
343  int32_t expected_message_sum = 0;
344  EXPECT_EQ(message_sum, expected_message_sum);
345 
346  // End tool contact
347  script_command_interface_->endToolContact();
348 
349  message.clear();
350  client_->readMessage(command, message);
351  // 6 is end tool contact
352  expected_command = 6;
353  EXPECT_EQ(command, expected_command);
354 
355  // The rest of the message should be zero
356  message_sum = std::accumulate(std::begin(message) + 25, std::end(message), 0);
357  EXPECT_EQ(message_sum, expected_message_sum);
358 }
359 
360 TEST_F(ScriptCommandInterfaceTest, test_tool_contact_callback)
361 {
362  // Wait for the client to connect to the server
363  waitForClientConnection();
364  script_command_interface_->setToolContactResultCallback(
365  std::bind(&ScriptCommandInterfaceTest::handleToolContactResult, this, std::placeholders::_1));
366 
368  client_->send(toUnderlying(send_result));
369  waitToolContactResult(send_result);
370 
371  EXPECT_EQ(toUnderlying(received_result_), toUnderlying(send_result));
372 
374  client_->send(toUnderlying(send_result));
375  waitToolContactResult(send_result);
376 
377  EXPECT_EQ(toUnderlying(received_result_), toUnderlying(send_result));
378 }
379 
380 int main(int argc, char* argv[])
381 {
382  ::testing::InitGoogleTest(&argc, argv);
383 
384  return RUN_ALL_TESTS();
385 }
ToolVoltage
Possible values for the tool voltage.
The ScriptCommandInterface class starts a TCPServer for a robot to connect to and this connection is ...
bool waitForClientConnection(bool client_connected=true, std::chrono::duration< double > timeout=std::chrono::milliseconds(1000))
std::array< double, 3 > vector3d_t
Definition: types.h:29
TEST_F(ScriptCommandInterfaceTest, test_zero_ft_sensor)
std::unique_ptr< control::ScriptCommandInterface > script_command_interface_
control::ToolContactResult received_result_
void readMessage(int32_t &command, std::vector< int32_t > &message)
bool waitToolContactResult(control::ToolContactResult result, int milliseconds=1000)
Class for TCP socket abstraction.
Definition: tcp_socket.h:48
constexpr std::underlying_type< E >::type toUnderlying(const E e) noexcept
Converts an enum type to its underlying type.
Definition: types.h:58
virtual bool open(int socket_fd, struct sockaddr *address, size_t address_len)
ToolContactResult
Types for encoding until tool contact execution result.
std::array< uint32_t, 6 > vector6uint32_t
Definition: types.h:32
int main(int argc, char *argv[])
std::array< double, 6 > vector6d_t
Definition: types.h:30
void handleToolContactResult(control::ToolContactResult result)


ur_client_library
Author(s): Thomas Timm Andersen, Simon Rasmussen, Felix Exner, Lea Steffen, Tristan Schnell
autogenerated on Tue Jul 4 2023 02:09:47