Go to the documentation of this file.00001 
00002 
00003 
00004 
00005 
00006 
00007 
00008 
00009 
00010 
00011 
00012 
00013 
00014 
00015 
00016 
00017 
00018 
00019 
00020 
00021 
00022 
00023 
00024 
00025 
00026 
00027 
00028 
00029 
00030 
00031 
00032 
00033 
00034 
00035 
00036 import roslib; roslib.load_manifest('tf2_visualization')
00037 import rospy
00038 
00039 import os
00040 import yaml
00041 import subprocess
00042 
00043 from tf2_msgs.srv import FrameGraph
00044 import tf2_ros
00045 import tf2
00046 
00047 import rosgraph.masterapi
00048 
00049 class TFInterface(object):
00050     def __init__(self, use_listener=True):
00051         self.buffer = tf2_ros.Buffer()
00052         
00053         self.selected_parent = None
00054         self.selected_child = None
00055         self.data = None
00056         self.data_timestamp = None
00057         self.namespace = 'local'
00058 
00059         if use_listener:
00060             self.listener = tf2_ros.TransformListener(self.buffer)
00061             rospy.wait_for_service('~tf2_frames')
00062             self.srv = rospy.ServiceProxy('~tf2_frames', FrameGraph, persistent=True)
00063             self.master = rosgraph.masterapi.Master(rospy.get_name())
00064         else:
00065             self.listener = None
00066             self.srv = None
00067             self.master = None
00068     
00069     def register_srv(self, namespace):
00070         if namespace == self.namespace:
00071             return
00072         
00073         if namespace == 'local':
00074             rospy.wait_for_service('~tf2_frames')
00075             self.srv = rospy.ServiceProxy('~tf2_frames', FrameGraph, persistent=True)
00076         else:
00077             rospy.wait_for_service(namespace + '/tf2_frames')
00078             self.srv = rospy.ServiceProxy(namespace + '/tf2_frames', FrameGraph, persistent=True)
00079             self.namespace = namespace
00080 
00081     def find_tf_namespaces(self):
00082         ns = []
00083         
00084         if self.master:
00085             services = self.master.getSystemState()[2]
00086             for name, providers in services:
00087                 
00088                 if name.find(rospy.get_name() + '/') == 0:
00089                     continue
00090                 index = name.rfind('tf2_frames')
00091                 if index > 0:
00092                     ns.append(name[:index-1])
00093             ns.sort()
00094         
00095         return ns
00096 
00097     def clear_detail(self):
00098         self.selected_parent = None
00099         self.selected_child = None
00100 
00101     def set_detail(self, detail):
00102         selected = detail.split('-')
00103         self.selected_parent = selected[0]
00104         self.selected_child = selected[1]
00105 
00106     def set_data_timestamp(self, timestamp):
00107         self.data_timestamp = timestamp
00108 
00109     def update_data(self, namespace, from_file=False):
00110         if not from_file:
00111             if namespace == 'local':
00112                 frame_yaml = self.buffer.all_frames_as_yaml()
00113             else:
00114                 self.register_srv(namespace)
00115                 frame_yaml = self.srv().frame_yaml
00116 
00117             if self.listener is not None:
00118                 self.data_timestamp = rospy.Time.now()
00119 
00120             self.data = yaml.load(frame_yaml)
00121         else:
00122             self.data = self._load_yaml_file(namespace)
00123 
00124     def _load_yaml_file(self, filename):
00125         if not filename:
00126             return
00127 
00128         with open(filename, 'r') as f:
00129             data = yaml.load(f)
00130         return data
00131 
00132     def save_yaml(self, full_name):
00133         if not full_name:
00134             return
00135 
00136         filename = full_name.rstrip('.tf')
00137         with open(filename+'.tf', 'w') as f:
00138             f.write(yaml.dump(self.data))
00139 
00140     def save_pdf(self, full_name):
00141         if not full_name:
00142             return
00143 
00144         filename = full_name.rstrip('.pdf')
00145         with open(filename+'.gv', 'w') as f:
00146             f.write(self._generate_dot(self.data, full_info=True))
00147         subprocess.Popen(('dot -Tpdf ' + filename + '.gv -o ' + filename + '.pdf').split(' ')).communicate()
00148         subprocess.Popen(('rm -rf ' + filename + '.gv').split(' ')).communicate()
00149 
00150     def get_dot(self):
00151         return self._generate_dot(self.data)
00152 
00153     def get_info(self):
00154         if self.selected_child:
00155             return self.data[self.selected_child]
00156         return ""
00157 
00158     def get_echo_string(self, target, source):
00159         try:
00160             msg = self.buffer.lookup_transform(target, source, rospy.Time())
00161             echo = 'Time: ' + str(msg.header.stamp) + '\n'
00162             echo += 'Target: ' + msg.header.frame_id + '\n'
00163             echo += 'Source: ' + msg.child_frame_id + '\n'
00164             echo += 'Translation: \n' + str(msg.transform.translation) + '\n'
00165             echo += 'Rotation Quaternion: \n' + str(msg.transform.rotation) + '\n'
00166             return echo
00167         except tf2.TransformException as e:
00168             return str(e)
00169 
00170     def get_frame_list(self):
00171         if not self.data:
00172             return []
00173 
00174         l = self.data.keys()
00175 
00176         
00177         for el in self.data:
00178             map = self.data[el]
00179             if not map['parent'] in self.data:
00180                 l.append(map['parent'])
00181 
00182         l.sort()
00183         return l
00184 
00185     def _generate_dot(self, data, full_info=False):
00186         if not data:
00187             return 'digraph G { "No tf data received" }'
00188 
00189         dot = 'digraph G {\n'
00190         for el in data: 
00191             map = data[el]
00192             node_color = 'white'
00193             arrow_color = 'black'
00194             if el == self.selected_parent:
00195                 node_color = 'green'
00196             if el == self.selected_child:
00197                 node_color = 'green'
00198                 arrow_color = 'green'
00199             dot += "\"" + el + "\""
00200             dot += '['
00201             dot += 'shape=ellipse style=filled fillcolor="' + node_color + '" '
00202             dot += 'URL="' + map['parent'] + '-' + el + '"] '
00203             dot += '"'+map['parent']+'" -> "'+el+'" [color="' + arrow_color + '"]'
00204             if full_info:
00205                 dot += '[label=" '
00206                 dot += 'Broadcaster: '+map['broadcaster']+'\\n'
00207                 dot += 'Average rate: '+str(map['rate'])+'\\n'
00208                 dot += 'Buffer length: '+str(map['buffer_length'])+'\\n' 
00209                 dot += 'Most recent transform: '+str(map['most_recent_transform'])+'\\n'
00210                 dot += 'Oldest transform: '+str(map['oldest_transform'])+'\\n'
00211                 dot += '"];\n'
00212             if not map['parent'] in data:
00213                 root = map['parent']
00214                 if map['parent'] == self.selected_parent:
00215                     dot += "\"" + root + "\"" + '[fillcolor="green" style="filled"]'
00216         dot += 'edge [style=invis];\n'
00217         dot += ' subgraph cluster_legend { style=bold; color=black; label ="view_frames Result";\n'
00218         dot += '"Recorded at time: '+str(self.data_timestamp)+'"[ shape=plaintext ] ;\n'
00219         dot += '}->"'+root+'";\n}'
00220 
00221         return dot