intersect_plane.py
Go to the documentation of this file.
00001 #!/usr/bin/env python
00002 # Copyright (c) 2013, Oregon State University
00003 # All rights reserved.
00004 
00005 # Redistribution and use in source and binary forms, with or without
00006 # modification, are permitted provided that the following conditions are met:
00007 #     * Redistributions of source code must retain the above copyright
00008 #       notice, this list of conditions and the following disclaimer.
00009 #     * Redistributions in binary form must reproduce the above copyright
00010 #       notice, this list of conditions and the following disclaimer in the
00011 #       documentation and/or other materials provided with the distribution.
00012 #     * Neither the name of the Oregon State University nor the
00013 #       names of its contributors may be used to endorse or promote products
00014 #       derived from this software without specific prior written permission.
00015 
00016 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
00017 # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
00018 # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
00019 # DISCLAIMED. IN NO EVENT SHALL OREGON STATE UNIVERSITY BE LIABLE FOR ANY
00020 # DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
00021 # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00022 # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
00023 # ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00024 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
00025 # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00026 
00027 # Author Dan Lazewatsky/lazewatd@engr.orst.edu
00028 import roslib; roslib.load_manifest('world_intersect')
00029 import rospy
00030 #from tabletop_object_detector.msg import Table
00031 from visualization_msgs.msg import Marker
00032 from geometry_msgs.msg import Point, PointStamped, PoseStamped
00033 from sensor_msgs.msg import PointCloud2
00034 import numpy as np
00035 from tf.transformations import quaternion_from_euler, euler_from_quaternion
00036 from math import sin, cos, pi
00037 import tf
00038 from pr2_python.pointclouds import xyz_array_to_pointcloud2
00039 
00040 def cast_ray(pose, plane, tfl):
00041     # assume the plane passes through table.pose
00042     # and the vector table.pose.x,table.pose.y,table.pose.z+1 is a
00043     # normal for the table in its frame
00044     
00045     # point
00046     q = np.array([
00047         plane.pose.position.x,
00048         plane.pose.position.y,
00049         plane.pose.position.z
00050     ])
00051     
00052     # normal
00053     m = q + [0,0,1]
00054     
00055     try:
00056         # pose.header.stamp = tfl.getLatestCommonTime(table.pose.header.frame_id, pose.header.frame_id)
00057         tfl.waitForTransform(plane.header.frame_id, pose.header.frame_id, rospy.Time(0), rospy.Duration.from_sec(5))
00058         pose.header.stamp = rospy.Time(0)
00059         pose_transformed = tfl.transformPose(plane.header.frame_id, pose)
00060     except tf.Exception, e:
00061         print 'trouble with tf lookup'
00062         print e.message
00063         return False
00064        
00065     # origin vector
00066     p = np.array([pose_transformed.pose.position.x, pose_transformed.pose.position.y, pose_transformed.pose.position.z])
00067     quat = (
00068         pose_transformed.pose.orientation.x,
00069         pose_transformed.pose.orientation.y,
00070         pose_transformed.pose.orientation.z,
00071         pose_transformed.pose.orientation.w
00072     )
00073     ax,ay,az = euler_from_quaternion(quat)
00074     # direction vector
00075     # a pose is basically spherical coordinates, so convert to cartesian
00076     d = np.array([
00077         -cos(az)*cos(ay),
00078         -sin(az)*cos(ay),
00079          sin(ay)
00080     ])
00081     # intersection
00082     #t = (q - p).dot(m) / d.dot(m)
00083     t = np.dot(q-p,m) / np.dot(d,m)
00084     if t < 0: # some normal must be flipped since t is normally > 0
00085         v = PointStamped()
00086         v.header = plane.header
00087         v.point.x, v.point.y, v.point.z = p + t*d
00088         return v
00089     return False
00090     
00091 class Intersector(object):
00092     def __init__(self, plane_frame):
00093         self.plane_frame = plane_frame
00094         self.pose        = None
00095         self.table_pose  = PoseStamped()
00096         self.rate        = rospy.Rate(20)
00097         self.tfl         = tf.TransformListener()
00098         self.int_pub2    = rospy.Publisher('intersected_points', PointCloud2)
00099         self.int_pub     = rospy.Publisher('intersected_point', PointStamped)
00100 
00101 
00102         self.table_pose.pose.orientation.w = 1.0
00103         self.table_pose.header.frame_id = plane_frame
00104 
00105     def pose_cb(self, pose):
00106         self.pose = pose
00107         
00108     # def table_cb(self, table):
00109     #     self.table = table
00110         
00111     def run(self):
00112         while not rospy.is_shutdown():
00113             if not self.pose: continue
00114             intersection = cast_ray(self.pose, self.table_pose, self.tfl)
00115             if intersection:
00116                 cloud = xyz_array_to_pointcloud2(np.array([[
00117                     intersection.point.x,
00118                     intersection.point.y,
00119                     intersection.point.z
00120                 ]]))
00121                 cloud.header.frame_id = self.plane_frame
00122                 cloud.header.stamp = self.pose.header.stamp
00123                 self.int_pub2.publish(cloud)
00124                 self.int_pub.publish(intersection)
00125                 self.rate.sleep()
00126     
00127 if __name__ == '__main__':
00128     rospy.init_node('intersect_plane')
00129     plane_frame = rospy.get_param('~plane_frame')
00130     print 'Plane frame = %s' % plane_frame
00131     intersector = Intersector(plane_frame)
00132     pose_sub  = rospy.Subscriber('pose',  PoseStamped, intersector.pose_cb)
00133     # table_sub = rospy.Subscriber('table', Table,       intersector.table_cb)
00134     intersector.run()


world_intersect
Author(s): Daniel Lazewatsky
autogenerated on Mon Oct 6 2014 10:19:35