$search
00001 #! /usr/bin/env python 00002 00003 import roslib; roslib.load_manifest("pr2_dremel_server") 00004 00005 00006 from math import * 00007 00008 import rospy 00009 import numpy 00010 import tf 00011 00012 import pdb 00013 00014 def arcPoints(center, start, angle, rotaxis, stepSize = 0.01): 00015 """ Given the center point, the start location on an arc, and the rotation angle and axis 00016 This function computes points along the arc 00017 center- center point of arc [ x, y, z] 00018 start - start point along arc [x,y,z] 00019 angle - theta to rotate about axis 00020 rotaxis - rotational axis 00021 stepsize = Optional parameter - radian increment of points along the arc 00022 """ 00023 # bring lists into numpy 00024 00025 c = list(center) 00026 s = list(start) 00027 c.extend([0]) 00028 s.extend([1]) 00029 centerp = numpy.array(c) 00030 startp = numpy.array(s) 00031 angle = numpy.array(angle) 00032 00033 #make the step size divide evenly into the angle that must be traversed 00034 steps = numpy.max(4, numpy.ceil(abs(angle)/stepSize)) 00035 stepAngle = angle/steps 00036 points = numpy.ones([steps+1, 4] ) 00037 00038 rot= tf.transformations.rotation_matrix(stepAngle, rotaxis) 00039 points[0] = (startp-centerp) 00040 00041 for i in range(1, len(points) ): 00042 points[i] = numpy.dot(rot, points[i-1]) 00043 00044 points = points+centerp 00045 return points[:,0:3] 00046 00047 def within(target, actual, tolerance): 00048 if (numpy.abs(target-actual) < tolerance): 00049 return true 00050 else: 00051 return false 00052 00053 def buildLineSegment(c, g): 00054 current = numpy.array(c) 00055 goal = numpy.array(g) 00056 dist = numpy.linalg.norm(goal - current) 00057 num_points = int(floor(dist / 20)) + 1 00058 inc = (1.0 / num_points) * (goal - current) 00059 points = [] 00060 for i in range(1, num_points): 00061 points.append(current + inc * i) 00062 00063 points.append(goal) 00064 00065 return numpy.array(points) 00066 00067 00068 # TODO: ignores cw / ccw distinction, instead it always takes shortest path along arc 00069 def buildArc(current, center, goal, cw): 00070 p1 = numpy.array(current) - numpy.array(center) 00071 p2 = numpy.array(goal) - numpy.array(center) 00072 00073 # the distance between current and center should be the same as between goal and center 00074 dist_current = sqrt(p1[1]*p1[1] + p1[2]*p1[2]) 00075 dist_goal = sqrt(p2[1]*p2[1] + p2[2]*p2[2]) 00076 if (abs(dist_current - dist_goal) > 0.01): 00077 print "#WARNING: arc is mis-specified" 00078 return numpy.array([goal]) 00079 00080 angle = atan2(p2[2], p2[1]) - atan2(p1[2], p1[1]) 00081 if (angle > pi): 00082 angle = angle - 2*pi 00083 00084 if (angle < -pi): 00085 angle = angle + 2*pi 00086 00087 arc = arcPoints(center, current, angle, [1,0,0], numpy.pi/25) 00088 return arc 00089 00090 def loadGCode(path): 00091 f = open(path) 00092 lines = f.readlines() 00093 points = [] #numpy.zeros([lines.__len__(), 3]) 00094 x = None 00095 y = None 00096 z = None 00097 i = None 00098 j = None 00099 c = 0 00100 00101 command = 'G01' 00102 add_point = False 00103 for line in lines: 00104 for token in line.split(): 00105 if (token == 'G00'): 00106 command = 'G01' 00107 if (token == 'G01'): 00108 command = 'G01' 00109 if (token == 'G02'): 00110 command = 'G02' 00111 if (token == 'G03'): 00112 command = 'G03' 00113 00114 if token[0] == 'X': 00115 x = float(token[1:]) 00116 add_point = True 00117 if token[0] == 'Y': 00118 y = float(token[1:]) 00119 add_point = True 00120 if token[0] == 'Z': 00121 z = float(token[1:]) 00122 add_point = True 00123 if token[0] == 'I': 00124 i = float(token[1:]) 00125 add_point = True 00126 if token[0] == 'J': 00127 j = float(token[1:]) 00128 add_point = True 00129 00130 if add_point and (x!=None) and (y!=None) and (z!=None): 00131 #pdb.set_trace() 00132 goal = [z,x,y] 00133 if (c == 0): 00134 current = list(goal) 00135 else: 00136 current = points[c-1] 00137 00138 if command == 'G01': 00139 pts = buildLineSegment(current, goal) 00140 for p in pts: 00141 points.append(p) 00142 c = c + 1 00143 if command == 'G02': # assumes I,J are relative to coordinates to current X,Y 00144 center = [z, current[1]+i, current[2]+j] 00145 pts = buildArc(current, center, goal, True).tolist() 00146 for p in pts: 00147 points.append(p) 00148 c = c + 1 00149 if command == 'G03': 00150 center = [z, current[1]+i, current[2]+j] 00151 pts = buildArc(current, center, goal, False).tolist() 00152 for p in pts: 00153 points.append(p) 00154 c = c + 1 00155 00156 # remove last 0's 00157 #while (pts[-1][1] == 0) and (pts[-1][2] == 0): 00158 # pts = pts[0:-2] 00159 00160 pts = numpy.array(points) 00161 return pts 00162 00163 def remove_duplicate_x(points): 00164 pts = [] 00165 prev = points[0] 00166 approach_x = prev[0] 00167 for p in points: 00168 if (p[0] != prev[0]) or (prev[0] != approach_x): 00169 pts.append(prev) 00170 prev = p 00171 return numpy.array(pts) 00172 00173 def remove_duplicates(points): 00174 pts = [] 00175 prev = numpy.array([-1, -1, -1]) 00176 for p in points: 00177 if (p != prev).any(): 00178 pts.append(p) 00179 prev = p 00180 return numpy.array(pts) 00181 00182 class Segment: 00183 def __init__(self): 00184 self.x = [] 00185 self.y = [] 00186 00187 def append(self, x, y): 00188 self.x.append(x) 00189 self.y.append(y) 00190 00191 def empty(self): 00192 return (self.x == []) 00193 00194 def points2segments(points): 00195 segments = [] 00196 segment = Segment() 00197 00198 approach_x = points[0][0] 00199 00200 for p in points: 00201 if p[0] == approach_x: 00202 if not segment.empty(): 00203 segments.append(segment) 00204 segment = Segment() 00205 else: 00206 segment.append(p[1], p[2]) 00207 00208 if segment != []: 00209 segments.append(segment) 00210 00211 return segments 00212 00213 def scale_points(pts, max_x, max_y): 00214 mx = pts.max(0) 00215 00216 pts_scaled = pts 00217 00218 x_scale = max_x / mx[1] 00219 y_scale = max_y / mx[2] 00220 00221 if (x_scale > y_scale): 00222 pts_scaled[:,1:] = pts_scaled[:,1:] * y_scale 00223 else: 00224 pts_scaled[:,1:] = pts_scaled[:,1:] * x_scale 00225 00226 return pts_scaled 00227 00228 def center_points(pts): 00229 center = (pts.max(0) + pts.min(0)) / 2 00230 center[0] = 0 #don't center z 00231 pts_centered = pts - center 00232 return pts_centered 00233 00234 def flip_y(pts): 00235 pts_flipped = pts; 00236 pts_flipped[:,2] = -pts[:,2] 00237 return pts_flipped 00238 00239 def handle_parse_gcode(req): 00240 flip_y = rospy.get_param("flip_y", False) 00241 max_x = rospy.get_param("max_x", 0.3) 00242 max_y = rospy.get_param("max_y", 0.3) 00243 00244 pts = loadGCode(req.path) 00245 pts = removeDuplicates(pts) 00246 pts = center_points(pts) 00247 pts = scale_points(pts, max_x, max_y) 00248 00249 if flip_y: 00250 pts = flip_y(pts) 00251 00252 resp = ParseGCodeResponse() 00253 resp.segments = points2segments(pts) 00254 00255 return resp 00256 00257 #def gcode_server(): 00258 # rospy.init_node("gcode_server") 00259 # s = rospy.Service("parse_gcode", ParseGCode, handle_parse_gcode) 00260 # rospy.spin() 00261 # 00262 ## Example how to call the parse_gcode service 00263 #def sample_client(): 00264 # path = "/home/duhadway/ros/repos/bosch-ros-pkg/adam/pr2plotter/data/BOSCH.ncd" 00265 # parse_gcode = rospy.ServiceProxy('parse_gcode', ParseGCode) 00266 # resp = parse_gcode.call(path) 00267 # for segment in segments: 00268 # plt.plot(segment.x, segment.y) 00269 # 00270 #if __name__ == "__main__": 00271 # gcode_server()