29 std::lock_guard<std::recursive_mutex> l(m_mutex);
31 m_transforms.push_back(
t);
37 std::lock_guard<std::recursive_mutex> l(m_mutex);
39 for (
size_t i = 0; i < m_transforms.size(); i++)
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))
44 m_transforms.erase(m_transforms.begin() + i);
54 std::lock_guard<std::recursive_mutex> l(m_mutex);
60 std::lock_guard<std::recursive_mutex> guard(m_mutex);
64 double tmpDT = m_now - m_prev;
66 if (tmpDT > m_deltaTMax) {
69 if (tmpDT < m_deltaTMin) {
89 getEnvelope(newStamp);
92 if (m_lastStamp.isValid() ==
false)
94 m_lastStamp = newStamp;
103 m_transforms.clear();
105 for (
int i = 0; i < bsize; i++)
122 m_transforms.push_back(
t);
130 m_lastStamp = newStamp;
135 std::lock_guard<std::recursive_mutex> guard(m_mutex);
149 std::lock_guard<std::recursive_mutex> guard(m_mutex);
157 std::lock_guard<std::recursive_mutex> guard(m_mutex);
159 min=m_deltaTMin*1000;
160 max=m_deltaTMax*1000;
174 std::lock_guard<std::recursive_mutex> l(m_mutex);
175 m_transforms.clear();
187 if (!this->open(local_streaming_name))
189 yCError(TRANSFORMCLIENT,
"open(): Could not open port %s, check network", local_streaming_name.c_str());
202 std::lock_guard<std::recursive_mutex> l(m_mutex);
203 return m_transforms.size();
208 std::lock_guard<std::recursive_mutex> l(m_mutex);
209 return m_transforms[idx];
215 std::lock_guard<std::mutex> lock (m_rpc_mutex);
218 bool ok = in.
read(connection);
224 if (request ==
"help")
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");
236 else if (request ==
"is_connected")
238 if (isConnectedWithServer())
247 else if (request ==
"reconnect")
249 if (reconnectWithServer())
258 else if (request ==
"list_frames")
260 std::vector<std::string> v;
261 this->getAllFrameIds(v);
263 out.
addString(
"List of available reference frames:");
272 else if (request ==
"get_transform")
278 this->getTransform(src, dst, m);
279 out.
addString(
"Transform from " + src +
" to " + dst +
" is: ");
282 else if (request ==
"list_ports")
285 if (m_array_of_ports.size()==0)
287 out.
addString(
"No ports are currently active");
289 for (
auto& m_array_of_port : m_array_of_ports)
293 std::string s = m_array_of_port->port.getName() +
" "+ m_array_of_port->transform_src +
" -> " + m_array_of_port->transform_dst;
298 else if (request ==
"publish_transform")
304 std::string format =
"matrix";
307 if (port_name[0] ==
'/') {
308 port_name.erase(port_name.begin());
310 std::string full_port_name = m_local_name +
"/" + port_name;
312 for (
auto& m_array_of_port : m_array_of_ports)
314 if (m_array_of_port && m_array_of_port->port.getName() == full_port_name)
320 if (this->frameExists(src)==
false)
322 out.
addString(
"Requested src frame " + src +
" does not exists.");
323 yCWarning(TRANSFORMCLIENT,
"Requested src frame %s does not exists.", src.c_str());
325 if (this->frameExists(dst)==
false)
327 out.
addString(
"Requested dst frame " + dst +
" does not exists.");
328 yCWarning(TRANSFORMCLIENT,
"Requested fst frame %s does not exists.", dst.c_str());
334 b->transform_dst = dst;
336 bool pret = b->port.open(full_port_name);
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) {
348 out.
addString(
"Operation failed. Unable to open port " + full_port_name +
".");
353 out.
addString(
"unable to perform operation");
356 else if (request ==
"unpublish_all")
358 for (
auto& m_array_of_port : m_array_of_ports)
360 m_array_of_port->port.close();
361 delete m_array_of_port;
362 m_array_of_port=
nullptr;
364 m_array_of_ports.clear();
365 if (m_array_of_ports.size() == 0) {
370 else if (request ==
"unpublish_transform")
374 if (port_name[0] ==
'/') {
375 port_name.erase(port_name.begin());
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++)
380 if ((*it)->port.getName() == port_name)
385 m_array_of_ports.erase(it);
392 out.
addString(
"Port " + full_port_name +
" has been closed.");
396 out.
addString(
"Port " + full_port_name +
" was not found.");
398 if (m_array_of_ports.size() == 0) {
404 yCError(TRANSFORMCLIENT,
"Invalid vocab received in TransformClient");
411 if (returnToSender !=
nullptr)
413 out.
write(*returnToSender);
417 yCError(TRANSFORMCLIENT) <<
"Invalid return to sender";
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.";
428 m_local_name.clear();
429 m_remote_name.clear();
433 m_streaming_connection_type =
"udp";
435 if (m_local_name ==
"")
437 yCError(TRANSFORMCLIENT,
"open(): Invalid local name");
440 if (m_remote_name ==
"")
442 yCError(TRANSFORMCLIENT,
"open(): Invalid remote name");
446 if (config.
check(
"period"))
448 m_period = config.
find(
"period").
asInt32() / 1000.0;
453 yCWarning(TRANSFORMCLIENT,
"Using default period of %f s" , m_period);
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";
462 if (!m_rpc_InterfaceToUser.open(m_local_rpcUser))
464 yCError(TRANSFORMCLIENT,
"open(): Could not open rpc port %s, check network", m_local_rpcUser.c_str());
468 if (!m_rpc_InterfaceToServer.open(m_local_rpcServer))
470 yCError(TRANSFORMCLIENT,
"open(): Could not open rpc port %s, check network", m_local_rpcServer.c_str());
475 bool ok = Network::connect(m_remote_streaming_name.c_str(), m_local_streaming_name.c_str(), m_streaming_connection_type.c_str());
478 yCError(TRANSFORMCLIENT,
"open(): Could not connect to %s", m_remote_streaming_name.c_str());
482 ok = Network::connect(m_local_rpcServer, m_remote_rpc);
485 yCError(TRANSFORMCLIENT,
"open(): Could not connect to %s", m_remote_rpc.c_str());
490 m_rpc_InterfaceToUser.setReader(*
this);
496 m_rpc_InterfaceToServer.close();
497 m_rpc_InterfaceToUser.close();
498 if (m_transform_storage !=
nullptr)
500 delete m_transform_storage;
501 m_transform_storage =
nullptr;
508 for (
size_t i = 0; i < m_transform_storage->size(); i++)
510 all_frames += (*m_transform_storage)[i].toString() +
" ";
515 TransformClient::ConnectionType TransformClient::getConnectionType(
const std::string &target_frame,
const std::string &source_frame, std::string* commonAncestor =
nullptr)
517 if (target_frame == source_frame) {
return IDENTITY;}
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))
528 if(ancestor == source_frame)
533 tar2root_vec.push_back(ancestor);
536 child = source_frame;
537 while(getParent(child, ancestor))
539 if(ancestor == target_frame)
544 src2root_vec.push_back(ancestor);
548 for(i = 0; i < tar2root_vec.size(); i++)
552 for(j = 0; j < src2root_vec.size(); j++)
554 if(a == src2root_vec[j])
570 return getConnectionType(target_frame, source_frame) != DISCONNECTED;
580 bool ret = m_rpc_InterfaceToServer.write(b, resp);
585 yCError(TRANSFORMCLIENT) <<
"clear(): Received error from server";
591 yCError(TRANSFORMCLIENT) <<
"clear(): Error on writing on rpc port";
596 m_transform_storage->clear();
602 for (
size_t i = 0; i < m_transform_storage->size(); i++)
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; }
612 for (
size_t i = 0; i < m_transform_storage->size();)
616 std::string frame_to_add = (*m_transform_storage)[i].src_frame_id;
617 for (
const auto&
id : ids)
620 if (
id == frame_to_add) {
goto search_dst;}
622 ids.push_back(frame_to_add);
627 std::string frame_to_add = (*m_transform_storage)[i].dst_frame_id;
628 for (
const auto&
id : ids)
631 if (
id == frame_to_add) {
goto search_end;}
633 ids.push_back(frame_to_add);
644 for (
size_t i = 0; i < m_transform_storage->size(); i++)
646 std::string par((*m_transform_storage)[i].dst_frame_id);
647 if (((*m_transform_storage)[i].dst_frame_id == frame_id))
650 parent_frame_id = (*m_transform_storage)[i].src_frame_id;
657 bool TransformClient::canExplicitTransform(
const std::string& target_frame_id,
const std::string& source_frame_id)
const
660 size_t i, tfVec_size;
661 std::lock_guard<std::recursive_mutex> l(tfVec.
m_mutex);
663 tfVec_size = tfVec.
size();
664 for (i = 0; i < tfVec_size; i++)
666 if (tfVec[i].dst_frame_id == target_frame_id && tfVec[i].src_frame_id == source_frame_id)
674 bool TransformClient::getChainedTransform(
const std::string& target_frame_id,
const std::string& source_frame_id,
yarp::sig::Matrix& transform)
const
677 size_t i, tfVec_size;
678 std::lock_guard<std::recursive_mutex> l(tfVec.
m_mutex);
680 tfVec_size = tfVec.
size();
681 for (i = 0; i < tfVec_size; i++)
683 if (tfVec[i].dst_frame_id == target_frame_id)
685 if (tfVec[i].src_frame_id == source_frame_id)
687 transform = tfVec[i].toMatrix();
693 if (getChainedTransform(tfVec[i].src_frame_id, source_frame_id, m))
695 transform = m * tfVec[i].toMatrix();
707 std::string ancestor;
708 ct = getConnectionType(target_frame_id, source_frame_id, &ancestor);
711 return getChainedTransform(target_frame_id, source_frame_id, transform);
713 else if (ct == INVERSE)
716 getChainedTransform(source_frame_id, target_frame_id, m);
720 else if(ct == UNDIRECT)
723 getChainedTransform(source_frame_id, ancestor, root2src);
724 getChainedTransform(target_frame_id, ancestor, root2tar);
728 else if (ct == IDENTITY)
735 yCError(TRANSFORMCLIENT) <<
"getTransform(): Frames " << source_frame_id <<
" and " << target_frame_id <<
" are not connected";
741 if(target_frame_id == source_frame_id)
743 yCError(TRANSFORMCLIENT) <<
"setTransform(): Invalid transform detected.\n" \
744 "\t Source frame and target frame are both equal to " << source_frame_id;
748 if (!canExplicitTransform(target_frame_id, source_frame_id) && canTransform(target_frame_id, source_frame_id))
750 yCError(TRANSFORMCLIENT) <<
"setTransform(): Such transform already exist by chaining transforms";
758 if (!
tf.fromMatrix(transform))
760 yCError(TRANSFORMCLIENT) <<
"setTransform(): Wrong matrix format, it has to be 4 by 4";
765 tf.src_frame_id = source_frame_id;
766 tf.dst_frame_id = target_frame_id;
780 bool ret = m_rpc_InterfaceToServer.write(b, resp);
785 yCError(TRANSFORMCLIENT) <<
"setTransform(): Received error from server on creating frame between " + source_frame_id +
" and " + target_frame_id;
791 yCError(TRANSFORMCLIENT) <<
"setTransform(): Error on writing on rpc port";
796 if (m_transform_storage)
798 if (m_transform_storage->set_transform(
tf) ==
false)
800 yCError(TRANSFORMCLIENT) <<
"setTransform(): Error while adding frame from local storage";
809 if(target_frame_id == source_frame_id)
811 yCError(TRANSFORMCLIENT) <<
"setTransformStatic(): Invalid transform detected.\n" \
812 "\t Source frame and target frame are both equal to " << source_frame_id;
816 if (canTransform(target_frame_id, source_frame_id))
818 yCError(TRANSFORMCLIENT) <<
"setTransform(): Such static transform already exist, directly or by chaining transforms";
826 if (!
tf.fromMatrix(transform))
828 yCError(TRANSFORMCLIENT) <<
"setTransform(): Wrong matrix format, it has to be 4 by 4";
833 tf.src_frame_id = source_frame_id;
834 tf.dst_frame_id = target_frame_id;
848 bool ret = m_rpc_InterfaceToServer.write(b, resp);
853 yCError(TRANSFORMCLIENT) <<
"setTransform(): Received error from server on creating frame between " + source_frame_id +
" and " + target_frame_id;
859 yCError(TRANSFORMCLIENT) <<
"setTransform(): Error on writing on rpc port";
864 if (m_transform_storage)
866 if (m_transform_storage->set_transform(
tf) ==
false)
868 yCError(TRANSFORMCLIENT) <<
"setTransformStatic(): Error while adding frame from local storage";
884 bool ret = m_rpc_InterfaceToServer.write(b, resp);
889 yCError(TRANSFORMCLIENT) <<
"Received error from server on deleting frame between "+source_frame_id+
" and "+target_frame_id;
895 yCError(TRANSFORMCLIENT) <<
"deleteFrame(): Error on writing on rpc port";
900 if (m_transform_storage)
902 if (m_transform_storage->delete_transform(target_frame_id, source_frame_id) ==
false)
904 yCError(TRANSFORMCLIENT) <<
"deleteFrame(): Error while removing frame from local storage";
914 if (input_point.
size() != 3)
916 yCError(TRANSFORMCLIENT) <<
"Only 3 dimensional vector allowed.";
920 if (!getTransform(target_frame_id, source_frame_id, m))
922 yCError(TRANSFORMCLIENT) <<
"No transform found between source '" << target_frame_id <<
"' and target '" << source_frame_id <<
"'";
927 transformed_point = m * in;
934 if (input_pose.
size() != 6)
936 yCError(TRANSFORMCLIENT) <<
"Only 6 dimensional vector (3 axes + roll pith and yaw) allowed.";
939 if (transformed_pose.
size() != 6)
941 yCWarning(TRANSFORMCLIENT,
"transformPose(): Performance warning: size transformed_pose should be 6, resizing.");
942 transformed_pose.
resize(6, 0.0);
945 if (!getTransform(target_frame_id, source_frame_id, m))
947 yCError(TRANSFORMCLIENT) <<
"No transform found between source '" << target_frame_id <<
"' and target '" << source_frame_id <<
"'";
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;
960 transformed_pose[3] = rot[0];
961 transformed_pose[4] = rot[1];
962 transformed_pose[5] = rot[2];
969 if (!getTransform(target_frame_id, source_frame_id, m))
971 yCError(TRANSFORMCLIENT) <<
"No transform found between source '" << target_frame_id <<
"' and target '" << source_frame_id <<
"'";
975 t.rotation=input_quaternion;
984 while (!canTransform(target_frame_id, source_frame_id))
988 yCError(TRANSFORMCLIENT) <<
"waitForTransform(): timeout expired";
997 m_transform_storage(nullptr),
1006 yCTrace(TRANSFORMCLIENT,
"Thread started");
1012 yCTrace(TRANSFORMCLIENT,
"Thread stopped");
1025 if (m_array_of_port)
1027 std::string src = m_array_of_port->transform_src;
1028 std::string dst = m_array_of_port->transform_dst;
1031 if (m_array_of_port->format ==
"matrix")
1033 m_array_of_port->port.write(m);
1037 yCError(TRANSFORMCLIENT) <<
"Unknown format requested: " << m_array_of_port->format;
1070 yCError(TRANSFORMCLIENT,
"reconnectWithServer(): Could not connect to %s",
m_remote_rpc.c_str());
constexpr yarp::conf::vocab32_t VOCAB_OK
constexpr yarp::conf::vocab32_t VOCAB_ERR
void fromRotationMatrix(const yarp::sig::Matrix &R)
Converts a rotation matrix to a quaternion.
A simple collection of objects that can be described and transmitted in a portable way.
void addVocab32(yarp::conf::vocab32_t x)
Places a vocabulary item in the bottle, at the end of the list.
size_type size() const
Gets the number of elements in the bottle.
bool read(ConnectionReader &reader) override
Set the bottle's value based on input from a network connection.
void addFloat64(yarp::conf::float64_t x)
Places a 64-bit floating point number in the bottle, at the end of the list.
Value & get(size_type index) const
Reads a Value v from a certain part of the list.
void clear()
Empties the bottle of any objects it contains.
bool write(ConnectionWriter &writer) const override
Output a representation of the bottle to a network connection.
void addString(const char *str)
Places a string in the bottle, at the end of the list.
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.
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.
static double nowSystem()
static void delaySystem(double seconds)
virtual yarp::conf::float64_t asFloat64() const
Get 64-bit floating point value.
virtual yarp::conf::vocab32_t asVocab32() const
Get vocabulary identifier as an integer.
virtual std::int32_t asInt32() const
Get 32-bit integer value.
virtual Bottle * asList() const
Get list value.
virtual std::string asString() const
Get string value.
std::string toString(int precision=-1, int width=-1, const char *endRowStr="\n") const
Print matrix to a string.
const Matrix & eye()
Build an identity matrix, don't resize.
void resize(size_t size) override
Resize the vector.
void push_back(const T &elem)
Push a new element in the vector: size is changed.
void pop_back()
Pop an element out of the vector: size is changed.
#define yCInfo(component,...)
#define yCError(component,...)
#define yCTrace(component,...)
#define yCWarning(component,...)
#define YARP_LOG_COMPONENT(name,...)
std::string to_string(IntegerType x)
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).
double now()
Return the current time in seconds, relative to an arbitrary starting point.
An interface to the operating system, including Port based communication.