dock_detect.py
Go to the documentation of this file.
1 #!/usr/bin/env python
2 
3 import random
4 import math
5 import struct
6 
7 import numpy as np
8 
9 import rospy
10 import tf.transformations
11 from sensor_msgs.msg import LaserScan
12 from sensor_msgs.msg import PointCloud
13 from sensor_msgs.msg import ChannelFloat32
14 from geometry_msgs.msg import Point32
15 from geometry_msgs.msg import PoseStamped
16 
17 import icp
18 
19 min_detect_angle = -0.87266 # now: -50 degree # -math.pi/4.0
20 max_detect_angle = 0.87266 # now: 50 degree # math.pi/4.0
21 
22 find_dock = False
23 cluster_threshold = 0.04 # cluster distance threshold
24 icp_distance_threshold = 0.01
25 potential_clouds_min_points = 80
26 
27 T = np.identity(4)
28 dock_pose = PoseStamped()
29 dock_pointcloud = PointCloud()
30 cluster_pointcloud = PointCloud()
31 ideal_dock_pointcloud = PointCloud()
32 
33 def Point32ToNumpy(points):
34  np_points = np.ones((len(points), 3))
35  for i in range(len(points)):
36  np_points[i][0] = points[i].x
37  np_points[i][1] = points[i].y
38  np_points[i][2] = points[i].z
39 
40  # rospy.loginfo(np_points)
41 
42  return np_points
43 
44 def GenerateIdealDock(points_count):
45  global ideal_dock_pointcloud
46 
47  # rospy.loginfo("GenerateIdealDock with %d points" % points_count)
48 
49  base_length = 0.40239 # 402.39mm
50  hypotenuse_length = 0.14 # 175.18mm
51  base_angle = math.pi / 3.0 * 2.0 # 120 degrees
52 
53  base_points_count = points_count/4*2 + points_count%4
54  hypotenuse_points_count = points_count / 4
55 
56  base_step_delta = base_length / base_points_count
57  hypotenuse_delta_x = math.sin(base_angle) * hypotenuse_length / hypotenuse_points_count
58  hypotenuse_delta_y = math.cos(base_angle) * hypotenuse_length / hypotenuse_points_count
59 
60  ideal_dock_cloud = []
61 
62  # right hypotenuse points
63  for i in range(hypotenuse_points_count):
64  point = Point32()
65  point.x = hypotenuse_delta_x * (hypotenuse_points_count-i) * (-1)
66  point.y = -(base_length/2.0) + hypotenuse_delta_y*(hypotenuse_points_count-i)
67  point.z = 0.0 # i * 0.01
68  ideal_dock_cloud.append(point)
69 
70  # base points
71  for i in range(base_points_count):
72  point = Point32(0.0, base_length/2.0-i*base_step_delta, 0.0)
73  ideal_dock_cloud.append(point)
74 
75  # left hypotenuse points
76  for i in range(hypotenuse_points_count):
77  point = Point32()
78  point.x = hypotenuse_delta_x * (hypotenuse_points_count-i) * (-1)
79  point.y = (base_length/2.0) - hypotenuse_delta_y*(hypotenuse_points_count-i)
80  point.z = 0.0 # i * 0.01
81  ideal_dock_cloud.append(point)
82 
83  # ideal dock pointcloud
84  ideal_dock_pointcloud = PointCloud()
85  ideal_dock_pointcloud.header.frame_id = "dock"
86  ideal_dock_pointcloud.header.stamp = rospy.Time.now()
87 
88  ideal_dock_pointcloud.points = ideal_dock_cloud
89 
90  return ideal_dock_cloud
91 
92 def callback(data):
93  global cluster_pointcloud, dock_pose, T, find_dock
94  angle_min = data.angle_min
95  angle_max = data.angle_max
96  angle_increment = data.angle_increment
97 
98  # rospy.loginfo("scan type, min angle: %f, max_angle: %f, increment: %f" % (angle_min, angle_max, angle_increment))
99  # rospy.loginfo("get scan data: %d points" % (len(data.ranges)))
100 
101  last_range = 0;
102  last_point = Point32()
103  cluster_index = 0
104 
105  clouds = []
106  potential_clouds = []
107 
108  for i in xrange(len(data.ranges)):
109  if (angle_min + i * angle_increment) >= min_detect_angle and (angle_min + i * angle_increment) <= max_detect_angle:
110  point = Point32()
111  point.x = math.cos(angle_min + i * angle_increment) * data.ranges[i];
112  point.y = math.sin(angle_min + i * angle_increment) * data.ranges[i];
113  point.z = 0
114 
115  distance = math.sqrt(math.pow(point.x-last_point.x,2)+math.pow(point.y-last_point.y,2))
116  if(distance > cluster_threshold):
117  if(len(clouds)>potential_clouds_min_points):
118  potential_clouds.append(clouds)
119  clouds = []
120 
121  clouds.append(point)
122 
123  last_point = point
124  last_range = data.ranges[i]
125 
126  # add last cloud into potential_clouds
127  # filter cloud with points count
128  if(len(clouds)>potential_clouds_min_points):
129  potential_clouds.append(clouds)
130 
131  if(len(potential_clouds)<=0):
132  find_dock = False
133  # rospy.logwarn("can not find dock")
134  return
135 
136  best_p_i = -1
137  best_distance = icp_distance_threshold
138  best_T = None
139  for p_i in xrange(len(potential_clouds)):
140  ideal_dock_cloud = GenerateIdealDock(len(potential_clouds[p_i]))
141 
142  ideal_dock_np = Point32ToNumpy(ideal_dock_cloud)
143  potential_cloud_np = Point32ToNumpy(potential_clouds[p_i])
144 
145  T, distance, i = icp.icp(ideal_dock_np, potential_cloud_np)
146 
147  mean_distance = np.mean(distance)
148  if mean_distance < icp_distance_threshold:
149  if(mean_distance < best_distance):
150  best_p_i = p_i
151  best_distance = mean_distance
152  best_T = T
153 
154  if best_p_i >= 0:
155  qt = tf.transformations.quaternion_from_matrix(best_T)
156 
157  find_dock = True
158  dock_pose = PoseStamped()
159  dock_pose.header.frame_id = "laser_link"
160  dock_pose.header.stamp = rospy.Time.now()
161  dock_pose.pose.position.x = best_T[0][3]
162  dock_pose.pose.position.y = best_T[1][3]
163  dock_pose.pose.position.z = best_T[2][3]
164  dock_pose.pose.orientation.x = qt[0]
165  dock_pose.pose.orientation.y = qt[1]
166  dock_pose.pose.orientation.z = qt[2]
167  dock_pose.pose.orientation.w = qt[3]
168  else:
169  find_dock = False
170 
171  # rospy.loginfo("icp distance %f" % np.mean(distance))
172  # rospy.loginfo(T)
173 
174  cluster_pointcloud = PointCloud()
175  cluster_pointcloud.header = data.header
176  cluster_pointcloud.header.stamp = rospy.Time.now()
177 
178  color_r = ChannelFloat32('rgb', [])
179  color_map = [0x00ff00, 0xffff00, 0xff00ff, 0x00ffff]
180 
181  for i in xrange(len(potential_clouds)):
182  for j in xrange(len(potential_clouds[i])):
183  cluster_pointcloud.points.append(potential_clouds[i][j])
184  color_r.values.append(color_map[i%4])
185 
186  cluster_pointcloud.channels.append(color_r)
187 
188 def main():
189  global cluster_pointcloud, ideal_dock_pointcloud, T, find_dock, dock_pose
190 
191  rospy.init_node('dock_detect', anonymous=True)
192 
193  rospy.Subscriber("scan", LaserScan, callback)
194 
195  dock_tf_broadcaster = tf.TransformBroadcaster()
196 
197  dock_pose_pub = rospy.Publisher('dock_pose', PoseStamped, queue_size=10)
198  dock_pointcloud_pub = rospy.Publisher('dock_pointcloud', PointCloud, queue_size=10)
199  cluster_pointcloud_pub = rospy.Publisher('cluster_pointcloud', PointCloud, queue_size=10)
200 
201  cluster_pointcloud = PointCloud()
202 
203  # dock_pose = PoseStamped();
204 
205  rate = rospy.Rate(40) # default 20Hz
206  while not rospy.is_shutdown():
207 
208  if(find_dock):
209  dock_tf_broadcaster.sendTransform(tf.transformations.translation_from_matrix(T), tf.transformations.quaternion_from_matrix(T), rospy.Time.now(), "dock", "laser_link")
210 
211  # orientation_q = dock_pose.pose.orientation
212  # orientation_list = [orientation_q.x, orientation_q.y, orientation_q.z, orientation_q.w]
213  # (r, p, y) = tf.transformations.euler_from_quaternion(orientation_list)
214  dock_pose.header.stamp = rospy.Time.now()
215  # dock_pose.pose.position.x += math.cos(y) * -0.5;
216  # dock_pose.pose.position.y += math.sin(y) * -0.5;
217  dock_pose_pub.publish(dock_pose)
218 
219  ideal_dock_pointcloud.header.stamp = rospy.Time.now()
220  dock_pointcloud_pub.publish(ideal_dock_pointcloud)
221 
222  cluster_pointcloud.header.stamp = rospy.Time.now()
223  cluster_pointcloud_pub.publish(cluster_pointcloud)
224 
225  rate.sleep()
226 
227 if __name__ == '__main__':
228  main()
def Point32ToNumpy(points)
Definition: dock_detect.py:33
def GenerateIdealDock(points_count)
Definition: dock_detect.py:44
def callback(data)
Definition: dock_detect.py:92
def icp(A, B, init_pose=None, max_iterations=20, tolerance=0.001)
Definition: icp.py:67


caster_app
Author(s): Ye Tian
autogenerated on Wed Dec 18 2019 03:34:44