00001
00002
00003 import roslib; roslib.load_manifest('door_perception')
00004 import rospy
00005 import numpy
00006 import tf
00007 import tf.transformations as tfm
00008 import sys
00009
00010 from articulation_msgs.msg import *
00011 from articulation_msgs.srv import *
00012 from geometry_msgs.msg import Pose, PoseStamped, Point, Quaternion
00013 from sensor_msgs.msg import ChannelFloat32
00014 from std_srvs.srv import Empty, EmptyResponse
00015 from door_perception.srv import DoorSrvResponse, DoorSrv
00016 from door_perception.msg import Door
00017
00018 def door_from_articulation_model(model):
00019 new_door = Door()
00020 isdoor = False
00021 for p in model.params:
00022 if p.name == "rot_center.x":
00023 new_door.axis.position.x = p.value
00024 isdoor = True
00025 if p.name == "rot_center.y":
00026 new_door.axis.position.y = p.value
00027 isdoor = True
00028 if p.name == "rot_center.z":
00029 new_door.axis.position.z = p.value
00030 isdoor = True
00031 if p.name == "rot_axis.x":
00032 new_door.axis.orientation.x = p.value
00033 isdoor = True
00034 if p.name == "rot_axis.y":
00035 new_door.axis.orientation.y = p.value
00036 isdoor = True
00037 if p.name == "rot_axis.z":
00038 new_door.axis.orientation.z = p.value
00039 isdoor = True
00040 if p.name == "rot_axis.w":
00041 new_door.axis.orientation.w = p.value
00042 isdoor = True
00043 if p.name == "rot_radius":
00044 new_door.radius = p.value
00045 isdoor = True
00046 if p.name == "rot_orientation.x":
00047 pass
00048 if p.name == "rot_orientation.y":
00049 pass
00050 if p.name == "rot_orientation.z":
00051 pass
00052 if p.name == "rot_orientation.w":
00053 pass
00054 if p.name == "rot_mode":
00055 pass
00056 if isdoor:
00057 new_door.header = model.header
00058 return new_door
00059
00060 def load_model(filename):
00061 result = ModelMsg()
00062 with open(filename, "r") as file:
00063 mystring = file.read()
00064 result.deserialize(mystring)
00065 rospy.loginfo("Deserialized Previous Model from " + filename)
00066 return result
00067
00068 def save_model(model_msg, filename):
00069 with open(filename, "w") as file:
00070 model_msg.serialize(file)
00071
00072 def set_model_prior(model):
00073 try:
00074 rospy.logdebug(str(model.params))
00075 model_prior_set = rospy.ServiceProxy('model_prior_set', SetModelPriorSrv)
00076 rospy.wait_for_service('model_prior_set', 10)
00077 request = SetModelPriorSrvRequest()
00078 request.model = [model]
00079 response = model_prior_set(request)
00080 except rospy.ServiceException, e:
00081 print "Service did not process request: %s"%str(e)
00082 except rospy.ROSException, e:
00083 print "Service did not come up: %s"%str(e)
00084
00085
00086
00087 class DoorNode:
00088 def __init__(self):
00089 self.model = ModelMsg()
00090 self.door = Door()
00091 self.setup_ros_communication()
00092
00093 self.model_file = rospy.get_param('~model_file', "")
00094 self.fixed_frame = rospy.get_param('~fixed_frame', "/odom_combined")
00095 self.load_door_model(self.model_file)
00096
00097
00098 def load_door_model_callback(self, request):
00099 filename = "model.msg"
00100 self.load_door_model(filename)
00101 return EmptyResponse()
00102
00103 def load_door_model(self, filename):
00104 try:
00105 loaded_model = load_model(filename)
00106 if len(loaded_model.track.pose) > 0:
00107 self.model = loaded_model
00108 self.model.header.stamp = rospy.get_rostime()
00109 self.model.id = 0
00110 rospy.loginfo("Setting Model")
00111 set_model_prior(self.model)
00112 self.pose_callback(None)
00113 except IOError as (errno, strerror):
00114 rospy.logwarn("I/O error({0}): {1} '".format(errno, strerror) + self.model_file +"'")
00115
00116
00117
00118 def save_door_model_callback(self, request):
00119 filename = "model.msg"
00120 self.save_door_model(filename)
00121 return EmptyResponse()
00122
00123 def save_door_model(self, filename):
00124 if(filename == ''):
00125 return
00126 rospy.loginfo("Saving model to " + filename)
00127 save_model(self.model, filename)
00128
00129 def pose_callback(self, pose_stamped):
00130 rospy.loginfo("Pose arrived")
00131
00132 try:
00133 request = TrackModelSrvRequest()
00134 if pose_stamped != None:
00135 pose_stamped.header.frame_id = pose_stamped.header.frame_id
00136 ff_pose_stamped = self.tfros.transformPose(self.fixed_frame, pose_stamped)
00137
00138
00139 self.model.track.header = ff_pose_stamped.header
00140 self.model.track.pose.append( ff_pose_stamped.pose )
00141 self.model.track.pose_headers.append( ff_pose_stamped.header )
00142
00143 try:
00144
00145 request.model = self.model
00146 response = self.model_select(request)
00147
00148
00149 loglikelihood = [entry.value for entry in response.model.params if entry.name=='loglikelihood'][0]
00150 q_min = [entry.value for entry in response.model.params if entry.name=='q_min[0]'][0]
00151 q_max = [entry.value for entry in response.model.params if entry.name=='q_max[0]'][0]
00152 rospy.loginfo("selected model: '%s' (n = %d, log LH = %f)" % (
00153 response.model.name, len(response.model.track.pose), loglikelihood))
00154 rospy.loginfo("Angular range: %f - %f" % (q_min, q_max))
00155
00156
00157 if response.model.name == 'rotational' and loglikelihood < 0.0:
00158 self.model_pub.publish(response.model)
00159
00160
00161
00162 door_raw = door_from_articulation_model(response.model)
00163 axis = PoseStamped()
00164 axis.pose = door_raw.axis
00165 axis.header = door_raw.header
00166 self.door_axis_pub2.publish(axis)
00167
00168 q = door_raw.axis.orientation
00169
00170 rot_to_min_q = tfm.quaternion_about_axis(-q_min, (0,0,1))
00171 zx_aligned = tfm.quaternion_multiply((q.x, q.y, q.z, q.w), rot_to_min_q)
00172 door_orientation = zx_aligned
00173
00174
00175
00176
00177
00178
00179
00180
00181
00182
00183 door_raw.axis.orientation.x = door_orientation[0]
00184 door_raw.axis.orientation.y = door_orientation[1]
00185 door_raw.axis.orientation.z = door_orientation[2]
00186 door_raw.axis.orientation.w = door_orientation[3]
00187 self.door = door_raw
00188 self.publish_door()
00189
00190 t = door_raw.axis.position
00191 handle2axis = tfm.translation_matrix((0, door_raw.radius, 0))
00192 axis2fixed = tfm.quaternion_matrix(door_orientation)
00193 axis2fixed[3,:] =(t.x, t.y, t.z, 1.0)
00194 handle2fixed = numpy.dot(axis2fixed , handle2axis)
00195
00196
00197
00198
00199
00200
00201
00202
00203
00204
00205 except rospy.ServiceException:
00206 print "model selection failed"
00207 pass
00208
00209 except tf.ExtrapolationException:
00210 rospy.loginfo("Skipped Pose, Transform from %s to %s not available"%(pose_stamped.header.frame_id, self.fixed_frame))
00211
00212 def publish_door(self):
00213
00214 axis = PoseStamped()
00215 axis.pose = self.door.axis
00216 axis.header = self.door.header
00217 self.door_axis_pub.publish(axis)
00218
00219 def door_service_callback(self, request):
00220 doors_response = DoorSrvResponse()
00221 doors_response.doors.append(self.door)
00222 return self.doors_response
00223
00224 def setup_ros_communication(self):
00225 self.tfros = tf.TransformListener()
00226 self.pose_subscriber = rospy.Subscriber("pose0", PoseStamped, self.pose_callback)
00227
00228 rospy.wait_for_service('model_select')
00229 self.model_select = rospy.ServiceProxy('model_select', TrackModelSrv)
00230 self.model_pub = rospy.Publisher('model', ModelMsg)
00231 self.door_axis_pub = rospy.Publisher('door_axis',PoseStamped)
00232 self.door_axis_pub2 = rospy.Publisher('door_axis2',PoseStamped)
00233 self.service = rospy.Service('door_description', DoorSrv, self.door_service_callback)
00234 self.service = rospy.Service('save_door_model', Empty, self.save_door_model_callback)
00235 self.service = rospy.Service('load_door_model', Empty, self.load_door_model_callback)
00236
00237
00238 if __name__ == '__main__':
00239 rospy.init_node('door_fitting')
00240 dn = DoorNode();
00241
00242
00243 r = rospy.Rate(10)
00244 while not rospy.is_shutdown():
00245 dn.publish_door()
00246
00247