4 ======================================================================================== 5 # This small script subscribes to the FeedbackMsg message of teb_local_planner 6 # and converts the current scene to a svg-image 7 # publish_feedback must be turned on such that the planner publishes this information. 8 # Author: christoph.roesmann@tu-dortmund.de 10 It is recommendable to start this node after initialization of TEB is completed. 13 svgwrite: A Python library to create SVG drawings. http://pypi.python.org/pypi/svgwrite 14 ======================================================================================= 22 from svgwrite
import cm, mm
23 from teb_local_planner.msg
import FeedbackMsg, TrajectoryMsg, TrajectoryPointMsg
24 from geometry_msgs.msg
import PolygonStamped, Point32, Quaternion
31 MIN_POSE_DISTANCE = 0.3
32 SCALE_VELOCITY_VEC = 0.4
39 OBSTACLE_DIST = 50 *SCALE/100
46 Signum function: get sign of a number 48 @param number: get sign of this number 49 @type number: numeric type (eg. integer) 50 @return: sign of number 51 @rtype: integer {1, -1, 0} 57 Create an arrow marker with svgwrite 60 @rtype: svg_write marker object 62 arrow = svg.marker(insert=(1,5), size=(4,3), orient=orientation)
63 arrow.viewbox(width=10, height=10)
64 arrow.add(svg.polyline([(0,0),(10,5),(0,10),(1,5)], fill=color, opacity=1.0))
70 Get yaw angle [degree] from quaternion representation 72 @param orientation: orientation in quaternions to read from 73 @type orientation: geometry_msgs/Quaternion 74 @return: yaw angle [degree] 77 yawRad = math.atan2(2*(orientation.x*orientation.y+orientation.z*orientation.w),1-2*(pow(orientation.y,2)+pow(orientation.z,2)))
78 return yawRad*180/math.pi
83 Callback for receiving TEB and obstacle information 85 @param data: Received feedback message 86 @type data: visualization_msgs/Marker 88 @globalparam tebList: Received TEB List 89 @globaltype tebList: teb_local_planner/FeedbackMsg 96 rospy.loginfo(
"TEB feedback message received...")
101 if __name__ ==
'__main__':
102 rospy.init_node(
'export_to_svg', anonymous=
True)
104 topic_name =
"/test_optim_node/teb_feedback" 106 rospy.Subscriber(topic_name, FeedbackMsg, feedback_callback, queue_size = 1)
108 rospy.loginfo(
"Waiting for feedback message on topic %s.", topic_name)
110 rate = rospy.Rate(10.0)
113 timestr = time.strftime(
"%Y%m%d_%H%M%S")
114 filename_string =
"teb_svg_" + timestr +
'.svg' 116 rospy.loginfo(
"SVG will be written to '%s'.", filename_string)
120 svg=svgwrite.Drawing(filename=filename_string, debug=
True)
123 svg.viewbox(GRID_X_MIN*SCALE-1*SCALE,GRID_Y_MIN*SCALE-1*SCALE,GRID_X_MAX*SCALE-GRID_X_MIN*SCALE+2*SCALE,GRID_Y_MAX*SCALE-GRID_Y_MIN*SCALE+2*SCALE)
126 hLines = svg.add(svg.g(id=
'hLines', stroke=
'black'))
127 hLines.add(svg.line(start=(GRID_X_MIN*SCALE, 0), end=(GRID_X_MAX*SCALE, 0)))
128 for y
in range(GRID_Y_MAX):
129 hLines.add(svg.line(start=(GRID_X_MIN*SCALE, SCALE+y*SCALE), end=(GRID_X_MAX*SCALE, SCALE+y*SCALE)))
130 for y
in range(-GRID_Y_MIN):
131 hLines.add(svg.line(start=(GRID_X_MIN*SCALE, -SCALE-y*SCALE), end=(GRID_X_MAX*SCALE, -SCALE-y*SCALE)))
132 vLines = svg.add(svg.g(id=
'vline', stroke=
'black'))
133 vLines.add(svg.line(start=(0, GRID_Y_MIN*SCALE), end=(0, GRID_Y_MAX*SCALE)))
134 for x
in range(GRID_X_MAX):
135 vLines.add(svg.line(start=(SCALE+x*SCALE, GRID_Y_MIN*SCALE), end=(SCALE+x*SCALE, GRID_Y_MAX*SCALE)))
136 for x
in range(-GRID_X_MIN):
137 vLines.add(svg.line(start=(-SCALE-x*SCALE, GRID_Y_MIN*SCALE), end=(-SCALE-x*SCALE, GRID_Y_MAX*SCALE)))
141 legend = svg.g(id=
'legend', font_size=25)
142 stringGeometry =
"Geometry: 1 Unit = 1.0m" 143 legendGeometry = svg.text(stringGeometry)
144 legend.add(legendGeometry)
145 legend.translate(tx=GRID_X_MIN*SCALE, ty=GRID_Y_MAX*SCALE + 30)
151 rospy.loginfo(
"Initialization completed.\nWaiting for feedback message...")
154 while not rospy.is_shutdown():
160 if not feedbackMsg.trajectories:
161 rospy.loginfo(
"Received message does not contain trajectories. Shutting down...")
164 if len(feedbackMsg.trajectories[0].trajectory) < 2:
165 rospy.loginfo(
"Received message does not contain trajectories with at least two states (start and goal). Shutting down...")
169 for index, traj
in enumerate(feedbackMsg.trajectories):
172 traj_color = svgwrite.rgb(random.randint(0, 255), random.randint(0, 255), random.randint(0, 255),
'RGB')
176 for point
in traj.trajectory:
177 points.append( (point.pose.position.x*SCALE,-point.pose.position.y*SCALE) )
181 if index == feedbackMsg.selected_trajectory_idx:
182 line = svg.add( svg.polyline(points=points, fill=
'none', stroke=traj_color, stroke_width=10, stroke_linecap=
'round', \
183 stroke_linejoin=
'round', opacity=1.0 ) )
185 line = svg.add( svg.polyline(points=points, fill=
'none', stroke=traj_color, stroke_width=10, stroke_linecap=
'butt', \
186 stroke_linejoin=
'round', stroke_dasharray=
'10,3', opacity=1.0 ) )
196 start_pose = feedbackMsg.trajectories[0].trajectory[0].pose
197 goal_pose = feedbackMsg.trajectories[0].trajectory[len(feedbackMsg.trajectories[0].trajectory)-1].pose
198 start_position = start_pose.position
199 goal_position = goal_pose.position
200 svg.add(svg.circle(center=(start_position.x*SCALE,-start_position.y*SCALE), r=10, stroke_width=1, stroke=
'blue', fill =
'blue'))
201 svg.add(svg.text(
"Start", (start_position.x*SCALE-70, -start_position.y*SCALE+45), font_size=35))
202 svg.add(svg.circle(center=(goal_position.x*SCALE,-goal_position.y*SCALE), r=10, stroke_width=1, stroke=
'red', fill =
'red'))
203 svg.add(svg.text(
"Goal", (goal_position.x*SCALE-40, -goal_position.y*SCALE+45), font_size=35))
206 start_arrow = svg.polyline([(0,-1),(6,-1),(5,-5),(15,0),(5,5),(6,1),(0,1)], fill=
'blue', opacity=1.0)
207 start_arrow.translate(start_position.x*SCALE,-start_position.y*SCALE)
213 goal_arrow = svg.polyline([(0,-1),(6,-1),(5,-5),(15,0),(5,5),(6,1),(0,1)], fill=
'red', opacity=1.0)
214 goal_arrow.translate(goal_position.x*SCALE,-goal_position.y*SCALE)
220 for obstacle
in feedbackMsg.obstacles:
221 if len(obstacle.polygon.points) == 1:
222 point = obstacle.polygon.points[0]
223 svg.add(svg.circle(center=(point.x*SCALE,-point.y*SCALE), r=OBSTACLE_DIST, stroke_width=1, stroke=
'grey', fill =
'grey', opacity=0.3))
224 svg.add(svg.circle(center=(point.x*SCALE,-point.y*SCALE), r=15, stroke_width=1, stroke=
'black', fill =
'black'))
225 svg.add(svg.text(
"Obstacle", (point.x*SCALE-70, -point.y*SCALE+45), font_size=35))
226 if len(obstacle.polygon.points) == 2:
227 line_start = obstacle.polygon.points[0]
228 line_end = obstacle.polygon.points[1]
229 svg.add(svg.line(start=(line_start.x*SCALE,-line_start.y*SCALE), end=(line_end.x*SCALE,-line_end.y*SCALE), stroke=
'black', fill=
'gray', stroke_width=1, opacity=1.0))
230 svg.add(svg.text(
"Obstacle", (line_start.x*SCALE-70, -line_start.y*SCALE+45), font_size=35))
231 if len(obstacle.polygon.points) > 2:
233 for point
in obstacle.polygon.points:
234 vertices.append((point.x*SCALE, -point.y*SCALE))
235 svg.add(svg.polygon(points=vertices, stroke=
'black', fill=
'gray', stroke_width=1, opacity=1.0))
236 svg.add(svg.text(
"Obstacle", (obstacle.polygon.points[0].x*SCALE-70, -obstacle.polygon.points.y*SCALE+45), font_size=35))
243 rospy.loginfo(
"Drawing completed.")
def arrowMarker(color='green', orientation='auto')
def quaternion2YawDegree(orientation)