6 #define _USE_MATH_DEFINES
17 #include <cmrc/cmrc.hpp>
29 #define LOG_THROTTLE_PERIOD 1.0
34 std::lock_guard<std::mutex> lock (m_rpc_mutex);
37 bool ok = in.
read(connection);
43 if (request ==
"help")
46 out.
addString(
"get_transform <src> <dst>: print the transform from <src> to <dst>");
47 out.
addString(
"list_transforms: print all the stored frame transforms");
48 out.
addString(
"list_frames: print all the available reference frames");
49 out.
addString(
"list_ports: print all the opened ports for transform broadcasting");
50 out.
addString(
"publish_transform <src> <dst> <portname> [format]: opens a port to publish transform from src to dst");
51 out.
addString(
"unpublish_transform <portname>: closes a previously opened port to publish a transform");
52 out.
addString(
"unpublish_all: closes a all previously opened ports to publish a transform");
53 out.
addString(
"set_static_transform_rad <src> <dst> <x> <y> <z> <roll> <pitch> <yaw>': create a static transform (angles in radians)");
54 out.
addString(
"set_static_transform_deg <src> <dst> <x> <y> <z> <roll> <pitch> <yaw>': create a static transform (angles in degrees)");
55 out.
addString(
"delete_static_transform <src> <dst>': delete a static transform");
56 out.
addString(
"generate_view <option>': generate a frames.pdf file showing the transform tree diagram.");
57 out.
addString(
" The following values are valid for option (default=none)");
58 out.
addString(
" 'show_rpy': show rotation as rpy angles");
59 out.
addString(
" 'show_quaterion:'show rotation as a quaternion");
60 out.
addString(
" 'show_matrix:'show rotation as a 3x3 rotation matrix");
62 else if (request ==
"list_frames")
64 std::vector<std::string> v;
65 this->getAllFrameIds(v);
67 out.
addString(
"List of available reference frames:");
76 else if (request ==
"get_transform")
82 this->getTransform(src, dst, m);
83 out.
addString(
"Transform from " + src +
" to " + dst +
" is: ");
86 else if (request ==
"list_ports")
89 if (m_array_of_ports.size()==0)
91 out.
addString(
"No ports are currently active");
93 for (
auto& m_array_of_port : m_array_of_ports)
97 std::string s = m_array_of_port->port.getName() +
" "+ m_array_of_port->transform_src +
" -> " + m_array_of_port->transform_dst;
102 else if (request ==
"publish_transform")
108 std::string format_s =
"matrix";
112 if (format_s ==
"matrix") {eformat = broadcast_port_t::format_t::matrix;}
113 else {
yCError(FRAMETRANSFORMCLIENT) <<
"Invalid format" << format_s <<
"using format `matrix`. Only `matrix` is currently supported."; }
115 if (port_name[0] ==
'/') {
116 port_name.erase(port_name.begin());
118 std::string full_port_name = m_local_name +
"/" + port_name;
121 if (this->frameExists(src) ==
false)
123 out.
addString(
"Requested src frame " + src +
" does not exists.");
124 yCWarning(FRAMETRANSFORMCLIENT,
"Requested src frame %s does not exists.", src.c_str());
126 if (this->frameExists(dst) ==
false)
128 out.
addString(
"Requested dst frame " + dst +
" does not exists.");
129 yCWarning(FRAMETRANSFORMCLIENT,
"Requested fst frame %s does not exists.", dst.c_str());
134 if (port_already_exists) {
yCError(FRAMETRANSFORMCLIENT,
"Requested port already exists!"); }
137 bool bcast_already_exists =
false;
138 for (
auto& m_array_of_port : m_array_of_ports)
140 if (m_array_of_port && m_array_of_port->port.getName() == full_port_name)
142 bcast_already_exists |=
true;
148 if (bcast_already_exists ==
false && port_already_exists ==
false)
152 b->transform_dst = dst;
154 bool pret = b->port.open(full_port_name);
157 out.
addString(
"Operation complete. Port " + full_port_name +
" opened.");
158 m_array_of_ports.push_back(b);
159 if (m_array_of_ports.size() == 1) {
166 out.
addString(
"Operation failed. Unable to open port " + full_port_name +
".");
171 out.
addString(
"unable to perform operation");
174 else if (request ==
"unpublish_all")
176 for (
auto& m_array_of_port : m_array_of_ports)
178 m_array_of_port->port.close();
179 delete m_array_of_port;
180 m_array_of_port=
nullptr;
182 m_array_of_ports.clear();
183 if (m_array_of_ports.size() == 0) {
188 else if (request ==
"unpublish_transform")
192 if (port_name[0] ==
'/') {
193 port_name.erase(port_name.begin());
195 std::string full_port_name = m_local_name +
"/" + port_name;
196 for (
auto it = m_array_of_ports.begin(); it != m_array_of_ports.end(); it++)
198 if ((*it)->port.getName() == port_name)
203 m_array_of_ports.erase(it);
210 out.
addString(
"Port " + full_port_name +
" has been closed.");
214 out.
addString(
"Port " + full_port_name +
" was not found.");
216 if (m_array_of_ports.size() == 0) {
220 else if (request ==
"set_static_transform_rad" ||
221 request ==
"set_static_transform_deg")
229 if (request ==
"set_static_transform_rad")
235 else if (request ==
"set_static_transform_deg")
242 bool ret = this->setTransformStatic(
t.src_frame_id,
t.dst_frame_id,
t.toMatrix());
245 yCInfo(FRAMETRANSFORMCLIENT) <<
"set_static_transform done";
246 out.
addString(
"set_static_transform done");
250 yCError(FRAMETRANSFORMCLIENT) <<
"read(): something strange happened";
254 else if (request ==
"generate_view")
256 m_show_transforms_in_diagram = show_transforms_in_diagram_t::do_not_show;
258 m_show_transforms_in_diagram = show_transforms_in_diagram_t::show_quaternion;
259 }
else if (in.
get(1).
asString() ==
"show_matrix") {
260 m_show_transforms_in_diagram = show_transforms_in_diagram_t::show_matrix;
262 m_show_transforms_in_diagram = show_transforms_in_diagram_t::show_rpy;
264 priv_generate_view();
267 else if (request ==
"delete_static_transform")
272 this->deleteTransform(src,dst);
273 out.
addString(
"delete_static_transform done");
277 yCError(FRAMETRANSFORMCLIENT,
"Invalid vocab received in FrameTransformClient");
284 if (returnToSender !=
nullptr)
286 out.
write(*returnToSender);
290 yCError(FRAMETRANSFORMCLIENT) <<
"Invalid return to sender";
297 yCWarning(FRAMETRANSFORMCLIENT) <<
"The 'FrameTransformClient' device is experimental and could be modified without any warning";
302 std::string configuration_to_open;
303 std::string innerFilePath=
"config_xml/ftc_local_only.xml";
304 auto fs = cmrc::frameTransformRC::get_filesystem();
305 if(cfg.
check(
"filexml_option")) { innerFilePath=
"config_xml/"+cfg.
find(
"filexml_option").
toString();}
306 cfg.
unput(
"filexml_option");
307 auto xmlFile =
fs.open(innerFilePath);
308 for(
const auto& lemma : xmlFile)
310 configuration_to_open += lemma;
313 std::string m_local_rpcUser =
"/ftClient/rpc";
315 cfg.
unput(
"local_rpc");
321 m_robot = std::move(result.
robot);
331 std::string setdeviceName =
"ftc_storage";
332 if (m_robot.hasParam(
"setDeviceName")) { setdeviceName = m_robot.findParam(
"setDeviceName");}
333 yCAssert(FRAMETRANSFORMCLIENT, m_robot.hasDevice(setdeviceName));
334 auto* polyset = m_robot.device(setdeviceName).driver();
335 yCAssert(FRAMETRANSFORMCLIENT, polyset);
336 polyset->view(m_ift_set);
337 yCAssert(FRAMETRANSFORMCLIENT, m_ift_set);
339 std::string getdeviceName =
"ftc_storage";
340 if (m_robot.hasParam(
"getDeviceName")) {getdeviceName = m_robot.findParam(
"getDeviceName");}
341 yCAssert(FRAMETRANSFORMCLIENT, m_robot.hasDevice(getdeviceName));
342 auto* polyget = m_robot.device(getdeviceName).driver();
343 yCAssert(FRAMETRANSFORMCLIENT, polyget);
344 polyget->view(m_ift_get);
345 yCAssert(FRAMETRANSFORMCLIENT, m_ift_get);
346 polyget->view(m_ift_util);
347 yCAssert(FRAMETRANSFORMCLIENT, m_ift_util);
349 if (config.
check(
"period"))
352 this->setPeriod(m_period);
355 if (!m_rpc_InterfaceToUser.open(m_local_rpcUser))
357 yCError(FRAMETRANSFORMCLIENT,
"Failed to open rpc port");
360 m_rpc_InterfaceToUser.setReader(*
this);
369 m_rpc_InterfaceToUser.close();
376 bool br = m_ift_util->getInternalContainer(p_cont);
377 if (!br || p_cont ==
nullptr) {
yCError(FRAMETRANSFORMCLIENT) <<
"Failure";
return false; }
380 std::lock_guard<std::recursive_mutex> l(p_cont->
m_trf_mutex);
383 for (
auto it = p_cont->
begin(); it != p_cont->
end(); it++)
385 all_frames += it->toString() +
" ";
390 FrameTransformClient::ConnectionType FrameTransformClient::priv_getConnectionType(
const std::string &target_frame,
const std::string &source_frame, std::string* commonAncestor =
nullptr)
392 if (target_frame == source_frame) {
return ConnectionType::IDENTITY;}
395 bool br = m_ift_util->getInternalContainer(p_cont);
396 if (!br || p_cont ==
nullptr) {
yCError(FRAMETRANSFORMCLIENT) <<
"Failure";
return ConnectionType::DISCONNECTED; }
399 std::vector<std::string> tar2root_vec;
400 std::vector<std::string> src2root_vec;
401 std::string ancestor, child;
402 child = target_frame;
405 std::lock_guard<std::recursive_mutex> l(p_cont->
m_trf_mutex);
408 while(getParent(child, ancestor))
410 if(ancestor == source_frame)
412 return ConnectionType::DIRECT;
415 tar2root_vec.push_back(ancestor);
418 child = source_frame;
419 while(getParent(child, ancestor))
421 if(ancestor == target_frame)
423 return ConnectionType::INVERSE;
426 src2root_vec.push_back(ancestor);
430 for(i = 0; i < tar2root_vec.size(); i++)
434 for(j = 0; j < src2root_vec.size(); j++)
436 if(a == src2root_vec[j])
442 return ConnectionType::UNDIRECT;
447 return ConnectionType::DISCONNECTED;
452 return priv_getConnectionType(target_frame, source_frame) != ConnectionType::DISCONNECTED;
459 return m_ift_set->clearAll();
461 yCError(FRAMETRANSFORMCLIENT,
"clear(): interface not available");
468 bool br = m_ift_util->getInternalContainer(p_cont);
469 if (!br || p_cont ==
nullptr) {
yCError(FRAMETRANSFORMCLIENT) <<
"Failure";
return false; }
472 std::lock_guard<std::recursive_mutex> l(p_cont->
m_trf_mutex);
475 for (
auto it = p_cont->
begin(); it != p_cont->
end(); it++)
477 if (it->src_frame_id == frame_id) {
return true; }
478 if (it->dst_frame_id == frame_id) {
return true; }
488 bool br = m_ift_util->getInternalContainer(p_cont);
489 if (!br || p_cont ==
nullptr) {
yCError(FRAMETRANSFORMCLIENT) <<
"Failure";
return false; }
492 std::lock_guard<std::recursive_mutex> l(p_cont->
m_trf_mutex);
495 for (
auto it = p_cont->
begin(); it != p_cont->
end(); it++)
498 for (
const auto&
id : ids)
500 if (it->src_frame_id ==
id) { found =
true;
break; }
502 if (found ==
false) {
503 ids.push_back(it->src_frame_id);
507 for (
auto it = p_cont->
begin(); it != p_cont->
end(); it++)
510 for (
const auto&
id : ids)
512 if (it->dst_frame_id ==
id) { found =
true;
break; }
514 if (found ==
false) {
515 ids.push_back(it->dst_frame_id);
525 bool br = m_ift_util->getInternalContainer(p_cont);
526 if (!br || p_cont ==
nullptr) {
yCError(FRAMETRANSFORMCLIENT) <<
"Failure";
return false; }
529 std::lock_guard<std::recursive_mutex> l(p_cont->
m_trf_mutex);
532 for (
auto it = p_cont->
begin(); it != p_cont->
end(); it++)
534 std::string par(it->dst_frame_id);
535 if (it->dst_frame_id == frame_id)
537 parent_frame_id = it->src_frame_id;
544 bool FrameTransformClient::priv_canExplicitTransform(
const std::string& target_frame_id,
const std::string& source_frame_id)
const
547 bool br = m_ift_util->getInternalContainer(p_cont);
548 if (!br || p_cont ==
nullptr) {
yCError(FRAMETRANSFORMCLIENT) <<
"Failure";
return false; }
551 std::lock_guard<std::recursive_mutex> l(p_cont->
m_trf_mutex);
554 for (
auto it = p_cont->
begin(); it != p_cont->
end(); it++)
556 if (it->dst_frame_id == target_frame_id && it->src_frame_id == source_frame_id)
564 bool FrameTransformClient::priv_getChainedTransform(
const std::string& target_frame_id,
const std::string& source_frame_id,
yarp::sig::Matrix& transform)
const
567 bool br = m_ift_util->getInternalContainer(p_cont);
568 if (!br || p_cont ==
nullptr) {
yCError(FRAMETRANSFORMCLIENT) <<
"Failure";
return false; }
571 std::lock_guard<std::recursive_mutex> l(p_cont->
m_trf_mutex);
574 for (
auto it = p_cont->
begin(); it != p_cont->
end(); it++)
576 if (it->dst_frame_id == target_frame_id)
578 if (it->src_frame_id == source_frame_id)
580 transform = it->toMatrix();
586 if (priv_getChainedTransform(it->src_frame_id, source_frame_id, m))
588 transform = m * it->toMatrix();
600 std::string ancestor;
601 ct = priv_getConnectionType(target_frame_id, source_frame_id, &ancestor);
602 if (ct == ConnectionType::DIRECT)
604 return priv_getChainedTransform(target_frame_id, source_frame_id, transform);
606 else if (ct == ConnectionType::INVERSE)
609 priv_getChainedTransform(source_frame_id, target_frame_id, m);
613 else if(ct == ConnectionType::UNDIRECT)
616 priv_getChainedTransform(source_frame_id, ancestor, root2src);
617 priv_getChainedTransform(target_frame_id, ancestor, root2tar);
621 else if (ct == ConnectionType::IDENTITY)
634 if(target_frame_id == source_frame_id)
637 "\t Source frame and target frame are both equal to " << source_frame_id;
641 if (!priv_canExplicitTransform(target_frame_id, source_frame_id) && canTransform(target_frame_id, source_frame_id))
651 if (!
tf.fromMatrix(transform))
657 tf.src_frame_id = source_frame_id;
658 tf.dst_frame_id = target_frame_id;
664 return m_ift_set->setTransform(
tf);
666 yCError(FRAMETRANSFORMCLIENT,
"setTransform(): interface not available");
672 if(target_frame_id == source_frame_id)
675 "\t Source frame and target frame are both equal to " << source_frame_id;
679 if (canTransform(target_frame_id, source_frame_id))
686 if (!
tf.fromMatrix(transform))
691 tf.src_frame_id = source_frame_id;
692 tf.dst_frame_id = target_frame_id;
698 return m_ift_set->setTransform(
tf);
700 yCError(FRAMETRANSFORMCLIENT,
"setTransformStatic(): interface not available");
708 return m_ift_set->deleteTransform(target_frame_id, source_frame_id);
710 yCError(FRAMETRANSFORMCLIENT,
"deleteTransform(): interface not available");
716 if (input_point.
size() != 3)
722 if (!getTransform(target_frame_id, source_frame_id, m))
729 transformed_point = m * in;
736 if (input_pose.
size() != 6)
741 if (transformed_pose.
size() != 6)
743 yCWarning(FRAMETRANSFORMCLIENT,
"transformPose(): Performance warning: size transformed_pose should be 6, resizing.");
744 transformed_pose.
resize(6, 0.0);
747 if (!getTransform(target_frame_id, source_frame_id, m))
753 t.transFromVec(input_pose[0], input_pose[1], input_pose[2]);
754 t.rotFromRPY(input_pose[3], input_pose[4], input_pose[5]);
755 t.fromMatrix(m *
t.toMatrix());
756 transformed_pose[0] =
t.translation.tX;
757 transformed_pose[1] =
t.translation.tY;
758 transformed_pose[2] =
t.translation.tZ;
762 transformed_pose[3] = rot[0];
763 transformed_pose[4] = rot[1];
764 transformed_pose[5] = rot[2];
771 if (!getTransform(target_frame_id, source_frame_id, m))
777 t.rotation=input_quaternion;
786 while (!canTransform(target_frame_id, source_frame_id))
790 yCError(FRAMETRANSFORMCLIENT) <<
"waitForTransform(): timeout expired";
807 yCTrace(FRAMETRANSFORMCLIENT,
"Thread started");
813 yCTrace(FRAMETRANSFORMCLIENT,
"Thread stopped");
828 std::string src = m_array_of_port->transform_src;
829 std::string dst = m_array_of_port->transform_dst;
834 m_array_of_port->port.write(m);
856 return std::string(
",label=\" ") +
t->toString(FrameTransform::display_transform_mode_t::rotation_as_quaternion) +
"\"";
860 return std::string(
",label=\" ") +
t->toString(FrameTransform::display_transform_mode_t::rotation_as_matrix) +
"\"";
864 return std::string(
",label=\" ") +
t->toString(FrameTransform::display_transform_mode_t::rotation_as_rpy) +
"\"";
867 yCError(FRAMETRANSFORMCLIENT) <<
"get_matrix_as_text() invalid option";
883 if (!br || p_cont ==
nullptr) {
yCError(FRAMETRANSFORMCLIENT) <<
"Failure";
return false; }
886 std::lock_guard<std::recursive_mutex> l(p_cont->
m_trf_mutex);
889 std::string dot_string =
"digraph G { ";
890 for (
auto it = p_cont->
begin(); it != p_cont->
end(); it++)
894 std::string trf_text = it->src_frame_id +
"->" +
895 it->dst_frame_id +
" " +
897 dot_string += trf_text +
'\n';
900 std::string legend =
"\n\
902 node[shape=plaintext]\n\
903 subgraph cluster_01 {\n\
904 label = \"Legend\";\n\
905 key[label=<<table border=\"0\" cellpadding=\"2\" cellspacing=\"0\" cellborder=\"0\">\n\
906 <tr><td align=\"right\" port=\"i1\">YARP timed transform</td></tr>\n\
907 <tr><td align=\"right\" port=\"i2\">YARP static transform</td></tr>\n\
909 key2[label=<<table border=\"0\" cellpadding=\"2\" cellspacing=\"0\" cellborder=\"0\">\n\
910 <tr><td port = \"i1\"> </td></tr>\n\
911 <tr><td port = \"i2\"> </td></tr>\n\
913 key:i1:e -> key2:i1:w [color = blue]\n\
914 key:i2:e -> key2:i2:w [color = blue, style=dashed]\n\
917 std::string command_string =
"printf '" + dot_string + legend +
"' | dot -Tpdf > frames.pdf";
918 #if defined (__linux__)
919 int ret = std::system(
"dot -V");
922 yCError(FRAMETRANSFORMCLIENT) <<
"dot executable not found. Please install graphviz.";
926 yCDebug(FRAMETRANSFORMCLIENT) <<
"Command string is:" << command_string;
927 ret = std::system(command_string.c_str());
930 yCError(FRAMETRANSFORMCLIENT) <<
"The following command failed to execute:" << command_string;
934 yCError(FRAMETRANSFORMCLIENT) <<
"Not yet implemented. Available only Linux";
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.
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.
static bool exists(const std::string &port, bool quiet=true, bool checkVer=true)
Check for a port to be ready and responsive.
An abstraction for a periodic thread.
A class for storing options and configuration information.
Value & find(const std::string &key) const override
Gets a value corresponding to a given keyword.
void fromString(const std::string &txt, bool wipe=true)
Interprets a string as a list of properties.
bool check(const std::string &key) const override
Check if there exists a property of the given name.
void unput(const std::string &key)
Remove the association from the given key to a value, if present.
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.
virtual std::string toString() const =0
Return a standard text representation of the content of the object.
static double nowSystem()
static void delaySystem(double seconds)
virtual yarp::conf::float64_t asFloat64() const
Get 64-bit floating point value.
std::string toString() const override
Return a standard text representation of the content of the object.
virtual std::string asString() const
Get string value.
Result of the parsing of XMLReader.
bool parsingIsSuccessful
True if the parsing was successful, false otherwise.
Robot robot
If parsingIsSuccessful is true, contains a valid robot instance.
XMLReaderResult getRobotFromString(const std::string &filename, const yarp::os::Searchable &config=yarp::os::Property())
Parse the XML description of a robotinterface from a string.
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 yCAssert(component, x)
#define yCTrace(component,...)
#define yCWarning(component,...)
#define yCDebug(component,...)
#define YARP_LOG_COMPONENT(name,...)
#define yCErrorThrottle(component, period,...)
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.