00001
00002
00003
00004
00005
00006
00007
00008
00009 import numpy
00010 import random
00011 from math import sqrt, atan, pi, degrees
00012
00013 import rospy
00014 import tf
00015 from tf.transformations import quaternion_from_euler
00016 from world_canvas_client import AnnotationCollection, WCFError
00017
00018 import nav_msgs.msg as nav_msgs
00019 import sensor_msgs.msg as sensor_msgs
00020 import geometry_msgs.msg as geometry_msgs
00021
00022 from python_qt_binding.QtCore import Signal, QObject, pyqtSlot
00023 import rocon_qt_library.utils as utils
00024
00025
00026 class SlamWidgetInterface(QObject):
00027
00028 map_received = Signal(nav_msgs.OccupancyGrid, name='map_received')
00029 scan_received = Signal(list)
00030 robot_pose_received = Signal(dict)
00031
00032 def __init__(self, map_received_slot=None, map_topic='map', scan_received_slot=None, scan_topic='scan', robot_pose_received_slot=None, robot_pose_topic='robot_pose', wc_namespace='world_canvas', map_saved_callbacks=None,_tf=None):
00033 super(SlamWidgetInterface, self).__init__()
00034 if map_received_slot is not None:
00035 self.map_received.connect(map_received_slot)
00036 if scan_received_slot is not None:
00037 self.scan_received.connect(scan_received_slot)
00038 if robot_pose_received_slot is not None:
00039 self.robot_pose_received.connect(robot_pose_received_slot)
00040
00041 self.map_saved_callbacks=[]
00042 if map_saved_callbacks is not None:
00043 self.map_saved_callbacks = map_saved_callbacks
00044
00045 self.destroyed.connect(self.close)
00046
00047 if _tf is None:
00048 self._tf = tf.TransformListener()
00049 else:
00050 self._tf = _tf
00051 self.wc_namespace = wc_namespace
00052 self.ac_handler = AnnotationCollection(srv_namespace=self.wc_namespace)
00053
00054 self.sub_map = rospy.Subscriber(map_topic, nav_msgs.OccupancyGrid, self.map_cb)
00055 self.sub_scan = rospy.Subscriber(scan_topic, sensor_msgs.LaserScan, self.scan_cb)
00056 self.sub_robot_pose = rospy.Subscriber(robot_pose_topic, geometry_msgs.PoseStamped, self.robot_pose_cb)
00057
00058 self.w = 0
00059 self.h = 0
00060 self.ori_x = 0
00061 self.ori_y = 0
00062 self.map_frame = None
00063
00064 def save_map(self, world='world', map_name='map'):
00065 annotation = utils.create_map_annotation(world, map_name, self.map_msg)
00066 success = True
00067 message = "Success"
00068 try:
00069 self.ac_handler.add(annotation, self.map_msg)
00070 self.ac_handler.save()
00071 except WCFError as e:
00072 success = False
00073 message = str(e)
00074
00075 for callback in self.map_saved_callbacks:
00076 callback((success, message))
00077
00078 def map_cb(self, msg):
00079 """
00080 Update the map
00081
00082 :param nav_msgs.OccupancyGrid msg: a map from system
00083 """
00084 self.map_frame = msg.header.frame_id
00085 self.resolution = msg.info.resolution
00086 self.w = msg.info.width
00087 self.h = msg.info.height
00088 self.ori_x = msg.info.origin.position.x
00089 self.ori_y = msg.info.origin.position.y
00090 self.map_msg = msg
00091 self.map_received.emit(msg)
00092
00093 def scan_cb(self, msg):
00094 """
00095 Update the scan
00096
00097 :param sensor_msgs.LaserScan msg: scans data from system
00098 """
00099 scans = []
00100 trans_ptc = None
00101 if self.map_frame:
00102 if not (msg.header.frame_id == self.map_frame or msg.header.frame_id == ''):
00103 try:
00104 self._tf.waitForTransform(msg.header.frame_id, self.map_frame, rospy.Time(), rospy.Duration(10))
00105 point_cloud = utils.laser_scan_to_point_cloud(msg,10)
00106 trans_ptc = self._tf.transformPointCloud(self.map_frame, point_cloud)
00107 except tf.Exception:
00108 rospy.logerr("TF Error")
00109 trans_ptc = None
00110 else:
00111 trans_ptc = utils.laser_scan_to_point_cloud(msg)
00112
00113 if trans_ptc:
00114 for pt in trans_ptc.points:
00115 dx = (pt.x - self.ori_x) / self.resolution - self.w
00116 dy = (pt.y - self.ori_y) / self.resolution
00117 scans.append((dx, dy))
00118 self.scan_received.emit(scans)
00119
00120 def robot_pose_cb(self, msg):
00121 """
00122 Update the robot_pose
00123
00124 :param geometry_msgs.PoseStamped msg: robot pose data from system
00125 """
00126
00127 trans_pose = None
00128 if self.map_frame:
00129 if not (msg.header.frame_id == self.map_frame or msg.header.frame_id == ''):
00130 try:
00131 self._tf.waitForTransform(msg.header.frame_id, self.map_frame, rospy.Time(), rospy.Duration(10))
00132 trans_pose = self._tf.transformPose(self.map_frame, msg)
00133 except tf.Exception:
00134 rospy.logerr("TF Error")
00135 trans_pose = None
00136 else:
00137 trans_pose = msg
00138
00139 if trans_pose:
00140 dx = (trans_pose.pose.position.x - self.ori_x) / self.resolution - self.w
00141 dy = (trans_pose.pose.position.y - self.ori_y) / self.resolution
00142 (droll, dpitch, dyaw) = tf.transformations.euler_from_quaternion([trans_pose.pose.orientation.x,
00143 trans_pose.pose.orientation.y,
00144 trans_pose.pose.orientation.z,
00145 trans_pose.pose.orientation.w])
00146 translated_robot_pose = {}
00147 translated_robot_pose['x'] = dx
00148 translated_robot_pose['y'] = dy
00149 translated_robot_pose['yaw'] = degrees(dyaw)
00150
00151 self.robot_pose_received.emit(translated_robot_pose)
00152
00153 def close(self):
00154 if self.sub_map:
00155 self.sub_map.unregister()
00156
00157 if self.sub_scan:
00158 self.sub_scan.unregister()
00159
00160 if self.sub_robot_pose:
00161 self.sub_robot_pose.unregister()
00162
00163 super(SlamWidgetInterface, self).close()
00164
00165 def save_settings(self, plugin_settings, instance_settings):
00166
00167 pass
00168
00169 def restore_settings(self, plugin_settings, instance_settings):
00170
00171 pass