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>
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
17using namespace yarp::dev;
18using namespace yarp::os;
19using namespace yarp::sig;
20using namespace yarp::math;
21
22
23namespace {
24YARP_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
35bool 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 {
101 m_state = IFrameTransform::TRANSFORM_OK;
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 {
128 m_state = IFrameTransform::TRANSFORM_TIMEOUT;
129 }
130 m_lastStamp = newStamp;
131}
132
134{
135 std::lock_guard<std::recursive_mutex> guard(m_mutex);
136
137 int ret = m_state;
138 if (ret != IFrameTransform::TRANSFORM_GENERAL_ERROR)
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
155void 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);
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 {
239 {
240 out.addString("yes");
241 }
242 else
243 {
244 out.addString("no");
245 }
246 }
247 else if (request == "reconnect")
248 {
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();
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.7 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();
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
463 {
464 yCError(TRANSFORMCLIENT, "open(): Could not open rpc port %s, check network", m_local_rpcUser.c_str());
465 return false;
466 }
467
469 {
470 yCError(TRANSFORMCLIENT, "open(): Could not open rpc port %s, check network", m_local_rpcServer.c_str());
471 return false;
472 }
473
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
491 return true;
492}
493
495{
498 if (m_transform_storage != nullptr)
499 {
500 delete m_transform_storage;
501 m_transform_storage = nullptr;
502 }
503 return true;
504}
505
506bool 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
515TransformClient::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
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
568bool 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
597 return true;
598}
599
600bool 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
610bool 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
642bool 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
657bool TransformClient::canExplicitTransform(const std::string& target_frame_id, const std::string& source_frame_id) const
658{
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
674bool TransformClient::getChainedTransform(const std::string& target_frame_id, const std::string& source_frame_id, yarp::sig::Matrix& transform) const
675{
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
704bool 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
739bool 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
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
807bool 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
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
875bool 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
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
912bool 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
932bool 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
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
966bool 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
980bool 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
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
yarp::os::Port m_rpc_InterfaceToServer
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.
std::string m_local_rpcUser
bool isConnectedWithServer() override
Returns true if the client is connected with the server, false otherwise.
yarp::os::Port m_rpc_InterfaceToUser
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::string m_remote_name
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.
std::string m_local_name
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
Transforms_client_storage * m_transform_storage
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
Callback method.
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:64
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
bool getEnvelope(PortReader &envelope) override
bool open(const std::string &name) override
void useCallback()
Use own onRead() method as callback.
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.
void askToStop()
Stop the thread.
bool start()
Call this to start the thread.
bool write(const PortWriter &writer, const PortWriter *callback=nullptr) const override
Write an object to the port.
Definition: Port.cpp:436
void setReader(PortReader &reader) override
Set an external reader for port data.
Definition: Port.cpp:511
void close() override
Stop port activity.
Definition: Port.cpp:363
bool open(const std::string &name) override
Start port operation, with a specific name, with automatically-chosen network parameters.
Definition: Port.cpp:79
A base class for nested structures that can be searched.
Definition: Searchable.h:63
virtual bool check(const std::string &key) const =0
Check if there exists a property of the given name.
virtual Value & find(const std::string &key) const =0
Gets a value corresponding to a given keyword.
An abstraction for a time stamp and/or sequence number.
Definition: Stamp.h:21
bool isValid() const
Check if this Stamp is valid.
Definition: Stamp.cpp:39
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:39
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:220
size_t size() const
Definition: Vector.h:321
void push_back(const T &elem)
Push a new element in the vector: size is changed.
Definition: Vector.h:248
void pop_back()
Pop an element out of the vector: size is changed.
Definition: Vector.h:276
#define yCInfo(component,...)
Definition: LogComponent.h:171
#define yCError(component,...)
Definition: LogComponent.h:213
#define yCTrace(component,...)
Definition: LogComponent.h:84
#define yCWarning(component,...)
Definition: LogComponent.h:192
#define YARP_LOG_COMPONENT(name,...)
Definition: LogComponent.h:76
Definition: FrameGraph.h:19
std::string to_string(IntegerType x)
Definition: numeric.h:115
For streams capable of holding different kinds of content, check what they actually have.
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.