YARP
Yet Another Robot Platform
transformClient.cpp
Go to the documentation of this file.
1 /*
2  * SPDX-FileCopyrightText: 2006-2021 Istituto Italiano di Tecnologia (IIT)
3  * SPDX-License-Identifier: LGPL-2.1-or-later
4  */
5 
6 #include "transformClient.h"
7 #include <yarp/os/Log.h>
8 #include <yarp/os/LogComponent.h>
9 #include <yarp/os/LogStream.h>
10 #include <yarp/math/Math.h>
11 #include <mutex>
12 
15 //example: yarpdev --device transformClient --local /transformClient --remote /transformServer
16 
17 using namespace yarp::dev;
18 using namespace yarp::os;
19 using namespace yarp::sig;
20 using namespace yarp::math;
21 
22 
23 namespace {
24 YARP_LOG_COMPONENT(TRANSFORMCLIENT, "yarp.device.transformClient")
25 }
26 
28 {
29  std::lock_guard<std::recursive_mutex> l(m_mutex);
30 
31  m_transforms.push_back(t);
32  return true;
33 }
34 
35 bool Transforms_client_storage::delete_transform(std::string t1, std::string t2)
36 {
37  std::lock_guard<std::recursive_mutex> l(m_mutex);
38 
39  for (size_t i = 0; i < m_transforms.size(); i++)
40  {
41  if ((m_transforms[i].dst_frame_id == t1 && m_transforms[i].src_frame_id == t2) ||
42  (m_transforms[i].dst_frame_id == t2 && m_transforms[i].src_frame_id == t1))
43  {
44  m_transforms.erase(m_transforms.begin() + i);
45  return true;
46  }
47  }
48 
49  return false;
50 }
51 
53 {
54  std::lock_guard<std::recursive_mutex> l(m_mutex);
55 }
56 
58 {
59  m_now = Time::now();
60  std::lock_guard<std::recursive_mutex> guard(m_mutex);
61 
62  if (m_count>0)
63  {
64  double tmpDT = m_now - m_prev;
65  m_deltaT += tmpDT;
66  if (tmpDT > m_deltaTMax) {
67  m_deltaTMax = tmpDT;
68  }
69  if (tmpDT < m_deltaTMin) {
70  m_deltaTMin = tmpDT;
71  }
72 
73  //compare network time
74  /*if (tmpDT*1000<TRANSFORM_TIMEOUT)
75  {
76  state = b.get(5).asInt32();
77  }
78  else
79  {
80  state = TRANSFORM_TIMEOUT;
81  }*/
82  }
83 
84  m_prev = m_now;
85  m_count++;
86 
87  m_lastBottle = b;
88  Stamp newStamp;
89  getEnvelope(newStamp);
90 
91  //initialization (first received data)
92  if (m_lastStamp.isValid() == false)
93  {
94  m_lastStamp = newStamp;
95  }
96 
97  //now compare timestamps
98  // if ((1000 * (newStamp.getTime() - m_lastStamp.getTime()))<TRANSFORM_TIMEOUT)
99  if (true)
100  {
102 
103  m_transforms.clear();
104  int bsize= b.size();
105  for (int i = 0; i < bsize; i++)
106  {
107  //this includes: timed yarp transforms, static yarp transforms, ros transforms
108  Bottle* bt = b.get(i).asList();
109  if (bt != nullptr)
110  {
112  t.src_frame_id = bt->get(0).asString();
113  t.dst_frame_id = bt->get(1).asString();
114  t.timestamp = bt->get(2).asFloat64();
115  t.translation.tX = bt->get(3).asFloat64();
116  t.translation.tY = bt->get(4).asFloat64();
117  t.translation.tZ = bt->get(5).asFloat64();
118  t.rotation.w() = bt->get(6).asFloat64();
119  t.rotation.x() = bt->get(7).asFloat64();
120  t.rotation.y() = bt->get(8).asFloat64();
121  t.rotation.z() = bt->get(9).asFloat64();
122  m_transforms.push_back(t);
123  }
124  }
125  }
126  else
127  {
129  }
130  m_lastStamp = newStamp;
131 }
132 
134 {
135  std::lock_guard<std::recursive_mutex> guard(m_mutex);
136 
137  int ret = m_state;
139  {
140  data = m_lastBottle;
141  stmp = m_lastStamp;
142  }
143 
144  return ret;
145 }
146 
148 {
149  std::lock_guard<std::recursive_mutex> guard(m_mutex);
150  int ret = m_count;
151  return ret;
152 }
153 
154 // time is in ms
155 void Transforms_client_storage::getEstFrequency(int &ite, double &av, double &min, double &max)
156 {
157  std::lock_guard<std::recursive_mutex> guard(m_mutex);
158  ite=m_count;
159  min=m_deltaTMin*1000;
160  max=m_deltaTMax*1000;
161  if (m_count<1)
162  {
163  av=0;
164  }
165  else
166  {
167  av=m_deltaT/m_count;
168  }
169  av=av*1000;
170 }
171 
173 {
174  std::lock_guard<std::recursive_mutex> l(m_mutex);
175  m_transforms.clear();
176 }
177 
179 {
180  m_count = 0;
181  m_deltaT = 0;
182  m_deltaTMax = 0;
183  m_deltaTMin = 1e22;
184  m_now = Time::now();
185  m_prev = m_now;
186 
187  if (!this->open(local_streaming_name))
188  {
189  yCError(TRANSFORMCLIENT, "open(): Could not open port %s, check network", local_streaming_name.c_str());
190  }
191  this->useCallback();
192 }
193 
195 {
196  this->interrupt();
197  this->close();
198 }
199 
201 {
202  std::lock_guard<std::recursive_mutex> l(m_mutex);
203  return m_transforms.size();
204 }
205 
207 {
208  std::lock_guard<std::recursive_mutex> l(m_mutex);
209  return m_transforms[idx];
210 };
211 
212 //------------------------------------------------------------------------------------------------------------------------------
214 {
215  std::lock_guard<std::mutex> lock (m_rpc_mutex);
216  yarp::os::Bottle in;
217  yarp::os::Bottle out;
218  bool ok = in.read(connection);
219  if (!ok) {
220  return false;
221  }
222 
223  std::string request = in.get(0).asString();
224  if (request == "help")
225  {
226  out.addVocab32("many");
227  out.addString("'get_transform <src> <dst>: print the transform from <src> to <dst>");
228  out.addString("'list_frames: print all the available reference frames");
229  out.addString("'list_ports: print all the opened ports for transform broadcasting");
230  out.addString("'publish_transform <src> <dst> <portname> <format>: opens a port to publish transform from src to dst");
231  out.addString("'unpublish_transform <portname>: closes a previously opened port to publish a transform");
232  out.addString("'unpublish_all <portname>: closes a all previously opened ports to publish a transform");
233  out.addString("'is_connected'");
234  out.addString("'reconnect'");
235  }
236  else if (request == "is_connected")
237  {
238  if (isConnectedWithServer())
239  {
240  out.addString("yes");
241  }
242  else
243  {
244  out.addString("no");
245  }
246  }
247  else if (request == "reconnect")
248  {
249  if (reconnectWithServer())
250  {
251  out.addString("successful");
252  }
253  else
254  {
255  out.addString("unsuccessful");
256  }
257  }
258  else if (request == "list_frames")
259  {
260  std::vector<std::string> v;
261  this->getAllFrameIds(v);
262  out.addVocab32("many");
263  out.addString("List of available reference frames:");
264  int count = 0;
265  for (auto& vec : v)
266  {
267  count++;
268  std::string str = std::to_string(count) + "- " + vec;
269  out.addString(str.c_str());
270  }
271  }
272  else if (request == "get_transform")
273  {
274  std::string src = in.get(1).asString();
275  std::string dst = in.get(2).asString();
276  out.addVocab32("many");
278  this->getTransform(src, dst, m);
279  out.addString("Transform from " + src + " to " + dst + " is: ");
280  out.addString(m.toString());
281  }
282  else if (request == "list_ports")
283  {
284  out.addVocab32("many");
285  if (m_array_of_ports.size()==0)
286  {
287  out.addString("No ports are currently active");
288  }
289  for (auto& m_array_of_port : m_array_of_ports)
290  {
291  if (m_array_of_port)
292  {
293  std::string s = m_array_of_port->port.getName() + " "+ m_array_of_port->transform_src + " -> " + m_array_of_port->transform_dst;
294  out.addString(s);
295  }
296  }
297  }
298  else if (request == "publish_transform")
299  {
300  out.addVocab32("many");
301  std::string src = in.get(1).asString();
302  std::string dst = in.get(2).asString();
303  std::string port_name = in.get(3).asString();
304  std::string format = "matrix";
305  if (in.size() > 4)
306  {format= in.get(4).asString();}
307  if (port_name[0] == '/') {
308  port_name.erase(port_name.begin());
309  }
310  std::string full_port_name = m_local_name + "/" + port_name;
311  bool ret = true;
312  for (auto& m_array_of_port : m_array_of_ports)
313  {
314  if (m_array_of_port && m_array_of_port->port.getName() == full_port_name)
315  {
316  ret = false;
317  break;
318  }
319  }
320  if (this->frameExists(src)==false)
321  {
322  out.addString("Requested src frame " + src + " does not exists.");
323  yCWarning(TRANSFORMCLIENT, "Requested src frame %s does not exists.", src.c_str());
324  }
325  if (this->frameExists(dst)==false)
326  {
327  out.addString("Requested dst frame " + dst + " does not exists.");
328  yCWarning(TRANSFORMCLIENT, "Requested fst frame %s does not exists.", dst.c_str());
329  }
330  if (ret == true)
331  {
332  auto* b = new broadcast_port_t;
333  b->transform_src = src;
334  b->transform_dst = dst;
335  b->format = format;
336  bool pret = b->port.open(full_port_name);
337  if (pret)
338  {
339  out.addString("Operation complete. Port " + full_port_name + " opened.");
340  m_array_of_ports.push_back(b);
341  if (m_array_of_ports.size() == 1) {
342  this->start();
343  }
344  }
345  else
346  {
347  delete b;
348  out.addString("Operation failed. Unable to open port " + full_port_name + ".");
349  }
350  }
351  else
352  {
353  out.addString("unable to perform operation");
354  }
355  }
356  else if (request == "unpublish_all")
357  {
358  for (auto& m_array_of_port : m_array_of_ports)
359  {
360  m_array_of_port->port.close();
361  delete m_array_of_port;
362  m_array_of_port=nullptr;
363  }
364  m_array_of_ports.clear();
365  if (m_array_of_ports.size() == 0) {
366  this->askToStop();
367  }
368  out.addString("Operation complete");
369  }
370  else if (request == "unpublish_transform")
371  {
372  bool ret = false;
373  std::string port_name = in.get(1).asString();
374  if (port_name[0] == '/') {
375  port_name.erase(port_name.begin());
376  }
377  std::string full_port_name = m_local_name + "/" + port_name;
378  for (auto it = m_array_of_ports.begin(); it != m_array_of_ports.end(); it++)
379  {
380  if ((*it)->port.getName() == port_name)
381  {
382  (*it)->port.close();
383  delete (*it);
384  (*it)=nullptr;
385  m_array_of_ports.erase(it);
386  ret = true;
387  break;
388  }
389  }
390  if (ret)
391  {
392  out.addString("Port " + full_port_name + " has been closed.");
393  }
394  else
395  {
396  out.addString("Port " + full_port_name + " was not found.");
397  }
398  if (m_array_of_ports.size() == 0) {
399  this->askToStop();
400  }
401  }
402  else
403  {
404  yCError(TRANSFORMCLIENT, "Invalid vocab received in TransformClient");
405  out.clear();
406  out.addVocab32(VOCAB_ERR);
407  out.addString("Invalid command name");
408  }
409 
410  yarp::os::ConnectionWriter *returnToSender = connection.getWriter();
411  if (returnToSender != nullptr)
412  {
413  out.write(*returnToSender);
414  }
415  else
416  {
417  yCError(TRANSFORMCLIENT) << "Invalid return to sender";
418  }
419  return true;
420 }
421 
423 {
424  yCWarning(TRANSFORMCLIENT) << "The 'transformClient' device is deprecated in favour of 'frameTransformClient'.";
425  yCWarning(TRANSFORMCLIENT) << "The old device is no longer supported, and it will be deprecated in YARP 3.6 and removed in YARP 4.";
426  yCWarning(TRANSFORMCLIENT) << "Please update your scripts.";
427 
428  m_local_name.clear();
429  m_remote_name.clear();
430 
431  m_local_name = config.find("local").asString();
432  m_remote_name = config.find("remote").asString();
433  m_streaming_connection_type = "udp";
434 
435  if (m_local_name == "")
436  {
437  yCError(TRANSFORMCLIENT, "open(): Invalid local name");
438  return false;
439  }
440  if (m_remote_name == "")
441  {
442  yCError(TRANSFORMCLIENT, "open(): Invalid remote name");
443  return false;
444  }
445 
446  if (config.check("period"))
447  {
448  m_period = config.find("period").asInt32() / 1000.0;
449  }
450  else
451  {
452  m_period = 0.010;
453  yCWarning(TRANSFORMCLIENT, "Using default period of %f s" , m_period);
454  }
455 
456  m_local_rpcServer = m_local_name + "/rpc:o";
457  m_local_rpcUser = m_local_name + "/rpc:i";
458  m_remote_rpc = m_remote_name + "/rpc";
459  m_remote_streaming_name = m_remote_name + "/transforms:o";
460  m_local_streaming_name = m_local_name + "/transforms:i";
461 
462  if (!m_rpc_InterfaceToUser.open(m_local_rpcUser))
463  {
464  yCError(TRANSFORMCLIENT, "open(): Could not open rpc port %s, check network", m_local_rpcUser.c_str());
465  return false;
466  }
467 
468  if (!m_rpc_InterfaceToServer.open(m_local_rpcServer))
469  {
470  yCError(TRANSFORMCLIENT, "open(): Could not open rpc port %s, check network", m_local_rpcServer.c_str());
471  return false;
472  }
473 
474  m_transform_storage = new Transforms_client_storage(m_local_streaming_name);
475  bool ok = Network::connect(m_remote_streaming_name.c_str(), m_local_streaming_name.c_str(), m_streaming_connection_type.c_str());
476  if (!ok)
477  {
478  yCError(TRANSFORMCLIENT, "open(): Could not connect to %s", m_remote_streaming_name.c_str());
479  return false;
480  }
481 
482  ok = Network::connect(m_local_rpcServer, m_remote_rpc);
483  if (!ok)
484  {
485  yCError(TRANSFORMCLIENT, "open(): Could not connect to %s", m_remote_rpc.c_str());
486  return false;
487  }
488 
489 
490  m_rpc_InterfaceToUser.setReader(*this);
491  return true;
492 }
493 
495 {
496  m_rpc_InterfaceToServer.close();
497  m_rpc_InterfaceToUser.close();
498  if (m_transform_storage != nullptr)
499  {
500  delete m_transform_storage;
501  m_transform_storage = nullptr;
502  }
503  return true;
504 }
505 
506 bool TransformClient::allFramesAsString(std::string &all_frames)
507 {
508  for (size_t i = 0; i < m_transform_storage->size(); i++)
509  {
510  all_frames += (*m_transform_storage)[i].toString() + " ";
511  }
512  return true;
513 }
514 
515 TransformClient::ConnectionType TransformClient::getConnectionType(const std::string &target_frame, const std::string &source_frame, std::string* commonAncestor = nullptr)
516 {
517  if (target_frame == source_frame) {return IDENTITY;}
518 
519  Transforms_client_storage& tfVec = *m_transform_storage;
520  size_t i, j;
521  std::vector<std::string> tar2root_vec;
522  std::vector<std::string> src2root_vec;
523  std::string ancestor, child;
524  child = target_frame;
525  std::lock_guard<std::recursive_mutex> l(tfVec.m_mutex);
526  while(getParent(child, ancestor))
527  {
528  if(ancestor == source_frame)
529  {
530  return DIRECT;
531  }
532 
533  tar2root_vec.push_back(ancestor);
534  child = ancestor;
535  }
536  child = source_frame;
537  while(getParent(child, ancestor))
538  {
539  if(ancestor == target_frame)
540  {
541  return INVERSE;
542  }
543 
544  src2root_vec.push_back(ancestor);
545  child = ancestor;
546  }
547 
548  for(i = 0; i < tar2root_vec.size(); i++)
549  {
550  std::string a;
551  a = tar2root_vec[i];
552  for(j = 0; j < src2root_vec.size(); j++)
553  {
554  if(a == src2root_vec[j])
555  {
556  if(commonAncestor)
557  {
558  *commonAncestor = a;
559  }
560  return UNDIRECT;
561  }
562  }
563  }
564 
565  return DISCONNECTED;
566 }
567 
568 bool TransformClient::canTransform(const std::string &target_frame, const std::string &source_frame)
569 {
570  return getConnectionType(target_frame, source_frame) != DISCONNECTED;
571 }
572 
574 {
575  //first delete it on the server
577  yarp::os::Bottle resp;
580  bool ret = m_rpc_InterfaceToServer.write(b, resp);
581  if (ret)
582  {
583  if (resp.get(0).asVocab32() != VOCAB_OK)
584  {
585  yCError(TRANSFORMCLIENT) << "clear(): Received error from server";
586  return false;
587  }
588  }
589  else
590  {
591  yCError(TRANSFORMCLIENT) << "clear(): Error on writing on rpc port";
592  return false;
593  }
594 
595  //then delete it also in the local client
596  m_transform_storage->clear();
597  return true;
598 }
599 
600 bool TransformClient::frameExists(const std::string &frame_id)
601 {
602  for (size_t i = 0; i < m_transform_storage->size(); i++)
603  {
604  if (((*m_transform_storage)[i].src_frame_id) == frame_id) { return true; }
605  if (((*m_transform_storage)[i].dst_frame_id) == frame_id) { return true; }
606  }
607  return false;
608 }
609 
610 bool TransformClient::getAllFrameIds(std::vector< std::string > &ids)
611 {
612  for (size_t i = 0; i < m_transform_storage->size();)
613  {
614  search_src:
615  {
616  std::string frame_to_add = (*m_transform_storage)[i].src_frame_id;
617  for (const auto& id : ids)
618  {
619  //if the frame already exists, skip it
620  if (id == frame_to_add) {goto search_dst;}
621  }
622  ids.push_back(frame_to_add);
623  }
624 
625  search_dst:
626  {
627  std::string frame_to_add = (*m_transform_storage)[i].dst_frame_id;
628  for (const auto& id : ids)
629  {
630  //if the frame already exists, skip it
631  if (id == frame_to_add) {goto search_end;}
632  }
633  ids.push_back(frame_to_add);
634  }
635 
636  search_end:
637  i++;
638  }
639  return true;
640 }
641 
642 bool TransformClient::getParent(const std::string &frame_id, std::string &parent_frame_id)
643 {
644  for (size_t i = 0; i < m_transform_storage->size(); i++)
645  {
646  std::string par((*m_transform_storage)[i].dst_frame_id);
647  if (((*m_transform_storage)[i].dst_frame_id == frame_id))
648  {
649 
650  parent_frame_id = (*m_transform_storage)[i].src_frame_id;
651  return true;
652  }
653  }
654  return false;
655 }
656 
657 bool TransformClient::canExplicitTransform(const std::string& target_frame_id, const std::string& source_frame_id) const
658 {
659  Transforms_client_storage& tfVec = *m_transform_storage;
660  size_t i, tfVec_size;
661  std::lock_guard<std::recursive_mutex> l(tfVec.m_mutex);
662 
663  tfVec_size = tfVec.size();
664  for (i = 0; i < tfVec_size; i++)
665  {
666  if (tfVec[i].dst_frame_id == target_frame_id && tfVec[i].src_frame_id == source_frame_id)
667  {
668  return true;
669  }
670  }
671  return false;
672 }
673 
674 bool TransformClient::getChainedTransform(const std::string& target_frame_id, const std::string& source_frame_id, yarp::sig::Matrix& transform) const
675 {
676  Transforms_client_storage& tfVec = *m_transform_storage;
677  size_t i, tfVec_size;
678  std::lock_guard<std::recursive_mutex> l(tfVec.m_mutex);
679 
680  tfVec_size = tfVec.size();
681  for (i = 0; i < tfVec_size; i++)
682  {
683  if (tfVec[i].dst_frame_id == target_frame_id)
684  {
685  if (tfVec[i].src_frame_id == source_frame_id)
686  {
687  transform = tfVec[i].toMatrix();
688  return true;
689  }
690  else
691  {
693  if (getChainedTransform(tfVec[i].src_frame_id, source_frame_id, m))
694  {
695  transform = m * tfVec[i].toMatrix();
696  return true;
697  }
698  }
699  }
700  }
701  return false;
702 }
703 
704 bool TransformClient::getTransform(const std::string& target_frame_id, const std::string& source_frame_id, yarp::sig::Matrix& transform)
705 {
706  ConnectionType ct;
707  std::string ancestor;
708  ct = getConnectionType(target_frame_id, source_frame_id, &ancestor);
709  if (ct == DIRECT)
710  {
711  return getChainedTransform(target_frame_id, source_frame_id, transform);
712  }
713  else if (ct == INVERSE)
714  {
715  yarp::sig::Matrix m(4, 4);
716  getChainedTransform(source_frame_id, target_frame_id, m);
717  transform = yarp::math::SE3inv(m);
718  return true;
719  }
720  else if(ct == UNDIRECT)
721  {
722  yarp::sig::Matrix root2tar(4, 4), root2src(4, 4);
723  getChainedTransform(source_frame_id, ancestor, root2src);
724  getChainedTransform(target_frame_id, ancestor, root2tar);
725  transform = yarp::math::SE3inv(root2src) * root2tar;
726  return true;
727  }
728  else if (ct == IDENTITY)
729  {
730  yarp::sig::Matrix tmp(4, 4); tmp.eye();
731  transform = tmp;
732  return true;
733  }
734 
735  yCError(TRANSFORMCLIENT) << "getTransform(): Frames " << source_frame_id << " and " << target_frame_id << " are not connected";
736  return false;
737 }
738 
739 bool TransformClient::setTransform(const std::string& target_frame_id, const std::string& source_frame_id, const yarp::sig::Matrix& transform)
740 {
741  if(target_frame_id == source_frame_id)
742  {
743  yCError(TRANSFORMCLIENT) << "setTransform(): Invalid transform detected.\n" \
744  "\t Source frame and target frame are both equal to " << source_frame_id;
745  return false;
746  }
747 
748  if (!canExplicitTransform(target_frame_id, source_frame_id) && canTransform(target_frame_id, source_frame_id))
749  {
750  yCError(TRANSFORMCLIENT) << "setTransform(): Such transform already exist by chaining transforms";
751  return false;
752  }
753 
755  yarp::os::Bottle resp;
757 
758  if (!tf.fromMatrix(transform))
759  {
760  yCError(TRANSFORMCLIENT) << "setTransform(): Wrong matrix format, it has to be 4 by 4";
761  return false;
762  }
763 
764  //first add it to the server
765  tf.src_frame_id = source_frame_id;
766  tf.dst_frame_id = target_frame_id;
767  tf.isStatic = false;
770  b.addString(source_frame_id);
771  b.addString(target_frame_id);
772  b.addFloat64(1000.0); //transform lifetime
773  b.addFloat64(tf.translation.tX);
774  b.addFloat64(tf.translation.tY);
775  b.addFloat64(tf.translation.tZ);
776  b.addFloat64(tf.rotation.w());
777  b.addFloat64(tf.rotation.x());
778  b.addFloat64(tf.rotation.y());
779  b.addFloat64(tf.rotation.z());
780  bool ret = m_rpc_InterfaceToServer.write(b, resp);
781  if (ret)
782  {
783  if (resp.get(0).asVocab32() != VOCAB_OK)
784  {
785  yCError(TRANSFORMCLIENT) << "setTransform(): Received error from server on creating frame between " + source_frame_id + " and " + target_frame_id;
786  return false;
787  }
788  }
789  else
790  {
791  yCError(TRANSFORMCLIENT) << "setTransform(): Error on writing on rpc port";
792  return false;
793  }
794 
795  //then add it also locally
796  if (m_transform_storage)
797  {
798  if (m_transform_storage->set_transform(tf) == false)
799  {
800  yCError(TRANSFORMCLIENT) << "setTransform(): Error while adding frame from local storage";
801  return false;
802  }
803  }
804  return true;
805 }
806 
807 bool TransformClient::setTransformStatic(const std::string &target_frame_id, const std::string &source_frame_id, const yarp::sig::Matrix &transform)
808 {
809  if(target_frame_id == source_frame_id)
810  {
811  yCError(TRANSFORMCLIENT) << "setTransformStatic(): Invalid transform detected.\n" \
812  "\t Source frame and target frame are both equal to " << source_frame_id;
813  return false;
814  }
815 
816  if (canTransform(target_frame_id, source_frame_id))
817  {
818  yCError(TRANSFORMCLIENT) << "setTransform(): Such static transform already exist, directly or by chaining transforms";
819  return false;
820  }
821 
823  yarp::os::Bottle resp;
825 
826  if (!tf.fromMatrix(transform))
827  {
828  yCError(TRANSFORMCLIENT) << "setTransform(): Wrong matrix format, it has to be 4 by 4";
829  return false;
830  }
831 
832  //first add it to the server
833  tf.src_frame_id = source_frame_id;
834  tf.dst_frame_id = target_frame_id;
835  tf.isStatic = true;
838  b.addString(source_frame_id);
839  b.addString(target_frame_id);
840  b.addFloat64(-1); //transform lifetime
841  b.addFloat64(tf.translation.tX);
842  b.addFloat64(tf.translation.tY);
843  b.addFloat64(tf.translation.tZ);
844  b.addFloat64(tf.rotation.w());
845  b.addFloat64(tf.rotation.x());
846  b.addFloat64(tf.rotation.y());
847  b.addFloat64(tf.rotation.z());
848  bool ret = m_rpc_InterfaceToServer.write(b, resp);
849  if (ret)
850  {
851  if (resp.get(0).asVocab32() != VOCAB_OK)
852  {
853  yCError(TRANSFORMCLIENT) << "setTransform(): Received error from server on creating frame between " + source_frame_id + " and " + target_frame_id;
854  return false;
855  }
856  }
857  else
858  {
859  yCError(TRANSFORMCLIENT) << "setTransform(): Error on writing on rpc port";
860  return false;
861  }
862 
863  //then add it also locally
864  if (m_transform_storage)
865  {
866  if (m_transform_storage->set_transform(tf) == false)
867  {
868  yCError(TRANSFORMCLIENT) << "setTransformStatic(): Error while adding frame from local storage";
869  return false;
870  }
871  }
872  return true;
873 }
874 
875 bool TransformClient::deleteTransform(const std::string &target_frame_id, const std::string &source_frame_id)
876 {
877  //first delete it on the server
879  yarp::os::Bottle resp;
882  b.addString(target_frame_id);
883  b.addString(source_frame_id);
884  bool ret = m_rpc_InterfaceToServer.write(b, resp);
885  if (ret)
886  {
887  if (resp.get(0).asVocab32()!=VOCAB_OK)
888  {
889  yCError(TRANSFORMCLIENT) << "Received error from server on deleting frame between "+source_frame_id+" and "+target_frame_id;
890  return false;
891  }
892  }
893  else
894  {
895  yCError(TRANSFORMCLIENT) << "deleteFrame(): Error on writing on rpc port";
896  return false;
897  }
898 
899  //then delete it also locally
900  if (m_transform_storage)
901  {
902  if (m_transform_storage->delete_transform(target_frame_id, source_frame_id) == false)
903  {
904  yCError(TRANSFORMCLIENT) << "deleteFrame(): Error while removing frame from local storage";
905  return false;
906  }
907  }
908 
909  return true;
910 }
911 
912 bool TransformClient::transformPoint(const std::string &target_frame_id, const std::string &source_frame_id, const yarp::sig::Vector &input_point, yarp::sig::Vector &transformed_point)
913 {
914  if (input_point.size() != 3)
915  {
916  yCError(TRANSFORMCLIENT) << "Only 3 dimensional vector allowed.";
917  return false;
918  }
919  yarp::sig::Matrix m(4, 4);
920  if (!getTransform(target_frame_id, source_frame_id, m))
921  {
922  yCError(TRANSFORMCLIENT) << "No transform found between source '" << target_frame_id << "' and target '" << source_frame_id << "'";
923  return false;
924  }
925  yarp::sig::Vector in = input_point;
926  in.push_back(1);
927  transformed_point = m * in;
928  transformed_point.pop_back();
929  return true;
930 }
931 
932 bool TransformClient::transformPose(const std::string &target_frame_id, const std::string &source_frame_id, const yarp::sig::Vector &input_pose, yarp::sig::Vector &transformed_pose)
933 {
934  if (input_pose.size() != 6)
935  {
936  yCError(TRANSFORMCLIENT) << "Only 6 dimensional vector (3 axes + roll pith and yaw) allowed.";
937  return false;
938  }
939  if (transformed_pose.size() != 6)
940  {
941  yCWarning(TRANSFORMCLIENT, "transformPose(): Performance warning: size transformed_pose should be 6, resizing.");
942  transformed_pose.resize(6, 0.0);
943  }
944  yarp::sig::Matrix m(4, 4);
945  if (!getTransform(target_frame_id, source_frame_id, m))
946  {
947  yCError(TRANSFORMCLIENT) << "No transform found between source '" << target_frame_id << "' and target '" << source_frame_id << "'";
948  return false;
949  }
951  t.transFromVec(input_pose[0], input_pose[1], input_pose[2]);
952  t.rotFromRPY(input_pose[3], input_pose[4], input_pose[5]);
953  t.fromMatrix(m * t.toMatrix());
954  transformed_pose[0] = t.translation.tX;
955  transformed_pose[1] = t.translation.tY;
956  transformed_pose[2] = t.translation.tZ;
957 
958  yarp::sig::Vector rot;
959  rot = t.getRPYRot();
960  transformed_pose[3] = rot[0];
961  transformed_pose[4] = rot[1];
962  transformed_pose[5] = rot[2];
963  return true;
964 }
965 
966 bool TransformClient::transformQuaternion(const std::string &target_frame_id, const std::string &source_frame_id, const yarp::math::Quaternion &input_quaternion, yarp::math::Quaternion &transformed_quaternion)
967 {
968  yarp::sig::Matrix m(4, 4);
969  if (!getTransform(target_frame_id, source_frame_id, m))
970  {
971  yCError(TRANSFORMCLIENT) << "No transform found between source '" << target_frame_id << "' and target '" << source_frame_id <<"'";
972  return false;
973  }
975  t.rotation=input_quaternion;
976  transformed_quaternion.fromRotationMatrix(m * t.toMatrix());
977  return true;
978 }
979 
980 bool TransformClient::waitForTransform(const std::string &target_frame_id, const std::string &source_frame_id, const double &timeout)
981 {
982  //loop until canTransform == true or timeout expires
983  double start = yarp::os::SystemClock::nowSystem();
984  while (!canTransform(target_frame_id, source_frame_id))
985  {
986  if (yarp::os::SystemClock::nowSystem() - start > timeout)
987  {
988  yCError(TRANSFORMCLIENT) << "waitForTransform(): timeout expired";
989  return false;
990  }
992  }
993  return true;
994 }
995 
997  m_transform_storage(nullptr),
998  m_period(0.01)
999 {
1000 }
1001 
1003 
1005 {
1006  yCTrace(TRANSFORMCLIENT, "Thread started");
1007  return true;
1008 }
1009 
1011 {
1012  yCTrace(TRANSFORMCLIENT, "Thread stopped");
1013 }
1014 
1016 {
1017  std::lock_guard<std::mutex> lock (m_rpc_mutex);
1018  if (m_array_of_ports.size()==0)
1019  {
1020  return;
1021  }
1022 
1023  for (auto& m_array_of_port : m_array_of_ports)
1024  {
1025  if (m_array_of_port)
1026  {
1027  std::string src = m_array_of_port->transform_src;
1028  std::string dst = m_array_of_port->transform_dst;
1030  this->getTransform(src, dst, m);
1031  if (m_array_of_port->format == "matrix")
1032  {
1033  m_array_of_port->port.write(m);
1034  }
1035  else
1036  {
1037  yCError(TRANSFORMCLIENT) << "Unknown format requested: " << m_array_of_port->format;
1038  }
1039  }
1040  }
1041 }
1042 
1044 {
1045  bool ok1 = Network::isConnected(m_local_rpcServer.c_str(), m_remote_rpc.c_str());
1046  if (!ok1) {
1047  yCInfo(TRANSFORMCLIENT) << m_local_rpcServer << "is not connected to: " << m_remote_rpc;
1048  }
1049 
1050  bool ok2 = Network::isConnected(m_remote_streaming_name.c_str(), m_local_streaming_name.c_str(),m_streaming_connection_type.c_str());
1051  if (!ok2) {
1052  yCInfo(TRANSFORMCLIENT) << m_remote_streaming_name << "is not connected to: " << m_local_streaming_name;
1053  }
1054 
1055  return ok1 && ok2;
1056 }
1057 
1059 {
1060  bool ok = Network::connect(m_remote_streaming_name.c_str(), m_local_streaming_name.c_str(), m_streaming_connection_type.c_str());
1061  if (!ok)
1062  {
1063  yCError(TRANSFORMCLIENT, "reconnectWithServer(): Could not connect to %s", m_remote_streaming_name.c_str());
1064  return false;
1065  }
1066 
1067  ok = Network::connect(m_local_rpcServer, m_remote_rpc);
1068  if (!ok)
1069  {
1070  yCError(TRANSFORMCLIENT, "reconnectWithServer(): Could not connect to %s", m_remote_rpc.c_str());
1071  return false;
1072  }
1073  return true;
1074 }
float t
constexpr yarp::conf::vocab32_t VOCAB_OK
Definition: GenericVocabs.h:15
constexpr yarp::conf::vocab32_t VOCAB_ERR
Definition: GenericVocabs.h:17
constexpr yarp::conf::vocab32_t VOCAB_TRANSFORM_DELETE
constexpr yarp::conf::vocab32_t VOCAB_TRANSFORM_SET
constexpr yarp::conf::vocab32_t VOCAB_TRANSFORM_DELETE_ALL
constexpr yarp::conf::vocab32_t VOCAB_ITRANSFORM
bool ret
bool canTransform(const std::string &target_frame, const std::string &source_frame) override
Test if a transform exists.
std::string m_remote_streaming_name
bool allFramesAsString(std::string &all_frames) override
Creates a debug string containing the list of all registered frames.
void run() override
Loop function.
bool clear() override
Removes all the registered transforms.
bool transformPoint(const std::string &target_frame_id, const std::string &source_frame_id, const yarp::sig::Vector &input_point, yarp::sig::Vector &transformed_point) override
Transform a point into the target frame.
bool read(yarp::os::ConnectionReader &connection) override
Read this object from a network connection.
bool isConnectedWithServer() override
Returns true if the client is connected with the server, false otherwise.
bool getAllFrameIds(std::vector< std::string > &ids) override
Gets a vector containing all the registered frames.
std::vector< broadcast_port_t * > m_array_of_ports
std::mutex m_rpc_mutex
bool waitForTransform(const std::string &target_frame_id, const std::string &source_frame_id, const double &timeout) override
Block until a transform from source_frame_id to target_frame_id is possible or it times out.
void threadRelease() override
Release method.
bool reconnectWithServer() override
Attempts to reconnect the client with the server.
bool setTransform(const std::string &target_frame_id, const std::string &source_frame_id, const yarp::sig::Matrix &transform) override
Register a transform between two frames.
std::string m_local_rpcServer
std::string m_streaming_connection_type
bool open(yarp::os::Searchable &config) override
Open the DeviceDriver.
bool setTransformStatic(const std::string &target_frame_id, const std::string &source_frame_id, const yarp::sig::Matrix &transform) override
Register a static transform between two frames.
bool close() override
Close the DeviceDriver.
bool transformQuaternion(const std::string &target_frame_id, const std::string &source_frame_id, const yarp::math::Quaternion &input_quaternion, yarp::math::Quaternion &transformed_quaternion) override
Transform a quaternion into the target frame.
bool deleteTransform(const std::string &target_frame_id, const std::string &source_frame_id) override
Deletes a transform between two frames.
std::string m_remote_rpc
bool transformPose(const std::string &target_frame_id, const std::string &source_frame_id, const yarp::sig::Vector &input_pose, yarp::sig::Vector &transformed_pose) override
Transform a Stamped Pose into the target frame.
bool getTransform(const std::string &target_frame_id, const std::string &source_frame_id, yarp::sig::Matrix &transform) override
Get the transform between two frames.
bool frameExists(const std::string &frame_id) override
Check if a frame exists.
bool threadInit() override
Initialization method.
std::string m_local_streaming_name
bool getParent(const std::string &frame_id, std::string &parent_frame_id) override
Get the parent of a frame.
void onRead(yarp::os::Bottle &v) override
bool set_transform(yarp::math::FrameTransform t)
int getLast(yarp::os::Bottle &data, yarp::os::Stamp &stmp)
std::recursive_mutex m_mutex
void getEstFrequency(int &ite, double &av, double &min, double &max)
Transforms_client_storage(std::string port_name)
bool delete_transform(std::string t1, std::string t2)
yarp::math::FrameTransform & operator[](std::size_t idx)
void fromRotationMatrix(const yarp::sig::Matrix &R)
Converts a rotation matrix to a quaternion.
Definition: Quaternion.cpp:162
A simple collection of objects that can be described and transmitted in a portable way.
Definition: Bottle.h:74
void addVocab32(yarp::conf::vocab32_t x)
Places a vocabulary item in the bottle, at the end of the list.
Definition: Bottle.cpp:164
size_type size() const
Gets the number of elements in the bottle.
Definition: Bottle.cpp:251
bool read(ConnectionReader &reader) override
Set the bottle's value based on input from a network connection.
Definition: Bottle.cpp:240
void addFloat64(yarp::conf::float64_t x)
Places a 64-bit floating point number in the bottle, at the end of the list.
Definition: Bottle.cpp:158
Value & get(size_type index) const
Reads a Value v from a certain part of the list.
Definition: Bottle.cpp:246
void clear()
Empties the bottle of any objects it contains.
Definition: Bottle.cpp:121
bool write(ConnectionWriter &writer) const override
Output a representation of the bottle to a network connection.
Definition: Bottle.cpp:230
void addString(const char *str)
Places a string in the bottle, at the end of the list.
Definition: Bottle.cpp:170
An interface for reading from a network connection.
virtual ConnectionWriter * getWriter()=0
Gets a way to reply to the message, if possible.
An interface for writing to a network connection.
An abstraction for a periodic thread.
A base class for nested structures that can be searched.
Definition: Searchable.h:66
virtual Value & find(const std::string &key) const =0
Gets a value corresponding to a given keyword.
virtual bool check(const std::string &key) const =0
Check if there exists a property of the given name.
An abstraction for a time stamp and/or sequence number.
Definition: Stamp.h:22
static double nowSystem()
Definition: SystemClock.cpp:34
static void delaySystem(double seconds)
Definition: SystemClock.cpp:29
virtual yarp::conf::float64_t asFloat64() const
Get 64-bit floating point value.
Definition: Value.cpp:222
virtual yarp::conf::vocab32_t asVocab32() const
Get vocabulary identifier as an integer.
Definition: Value.cpp:228
virtual std::int32_t asInt32() const
Get 32-bit integer value.
Definition: Value.cpp:204
virtual Bottle * asList() const
Get list value.
Definition: Value.cpp:240
virtual std::string asString() const
Get string value.
Definition: Value.cpp:234
A class for a Matrix.
Definition: Matrix.h:43
std::string toString(int precision=-1, int width=-1, const char *endRowStr="\n") const
Print matrix to a string.
Definition: Matrix.cpp:171
const Matrix & eye()
Build an identity matrix, don't resize.
Definition: Matrix.cpp:456
void resize(size_t size) override
Resize the vector.
Definition: Vector.h:222
size_t size() const
Definition: Vector.h:323
void push_back(const T &elem)
Push a new element in the vector: size is changed.
Definition: Vector.h:250
void pop_back()
Pop an element out of the vector: size is changed.
Definition: Vector.h:278
#define yCInfo(component,...)
Definition: LogComponent.h:132
#define yCError(component,...)
Definition: LogComponent.h:154
#define yCTrace(component,...)
Definition: LogComponent.h:85
#define yCWarning(component,...)
Definition: LogComponent.h:143
#define YARP_LOG_COMPONENT(name,...)
Definition: LogComponent.h:77
Definition: FrameGraph.h:19
std::string to_string(IntegerType x)
Definition: numeric.h:115
An interface for the device drivers.
yarp::sig::Matrix SE3inv(const yarp::sig::Matrix &H)
Returns the inverse of a 4 by 4 rototranslational matrix (defined in Math.h).
Definition: math.cpp:912
double now()
Return the current time in seconds, relative to an arbitrary starting point.
Definition: Time.cpp:121
An interface to the operating system, including Port based communication.
Signal processing.
Definition: Image.h:22