00001
00002 import os
00003 import signal
00004 import sys
00005 import math
00006 import string
00007 import time
00008 import threading
00009
00010 import rospy
00011 import roslib; roslib.load_manifest('plot_util')
00012 import rosbag
00013 import tf
00014 from tf.transformations import euler_from_quaternion, quaternion_from_euler
00015
00016 from std_msgs.msg import *
00017 from nav_msgs.msg import *
00018
00019 import numpy as np
00020 import matplotlib.pyplot as plt
00021 import matplotlib.cm as cm
00022 from matplotlib.path import Path
00023 import matplotlib.patches as patches
00024 from matplotlib.backends.backend_pdf import PdfPages
00025 from matplotlib.font_manager import FontProperties
00026 from pylab import *
00027
00028 from data_odometry import *
00029
00030 from docutils.nodes import header
00031 from genpy import rostime
00032
00033
00034 class PlotsGenerator(object):
00035
00036
00037 def __init__(self):
00038 rospy.loginfo("[PlotsGenerator] init()")
00039
00040 self.dataOdom = DataOdometry()
00041
00042
00043 def threePlotsOnePage(self, pdf, title, ylabel1, ylabel2, ylabel3, xlabel, xData, yData1, yData2, yData3):
00044
00045 figure(figsize=(6,6))
00046
00047
00048 plt.subplot(3, 1, 1)
00049 plt.plot(xData, yData1)
00050
00051 plt.title(title)
00052 plt.ylabel(ylabel1)
00053 plt.grid(True)
00054
00055 setp(getp(gca(), 'xticklabels'), fontsize='x-small')
00056 setp(getp(gca(), 'yticklabels'), fontsize='x-small')
00057
00058
00059
00060 plt.subplot(3, 1, 2)
00061 plt.plot(xData, yData2)
00062
00063 plt.ylabel(ylabel2)
00064 plt.grid(True)
00065
00066 setp(getp(gca(), 'xticklabels'), fontsize='x-small')
00067 setp(getp(gca(), 'yticklabels'), fontsize='x-small')
00068
00069
00070
00071 plt.subplot(3, 1, 3)
00072 plt.plot(xData, yData3)
00073
00074 plt.ylabel(ylabel3)
00075 plt.grid(True)
00076
00077 setp(getp(gca(), 'xticklabels'), fontsize='x-small')
00078 setp(getp(gca(), 'yticklabels'), fontsize='x-small')
00079
00080
00081 plt.xlabel(xlabel)
00082
00083 plt.tight_layout()
00084 pdf.savefig()
00085 close()
00086
00087
00088
00089 def altitudeTimePlot(self, pdf, dataTime, dataZ):
00090 rospy.loginfo('<<< Plot Altitude x Time >>>')
00091
00092 figure(figsize=(6,6))
00093
00094 fig = plt.figure()
00095 ax = fig.add_subplot(111)
00096
00097 for i in range(len(dataZ)):
00098 dataZ[i] = dataZ[i]
00099
00100 plot(dataTime, dataZ)
00101
00102 xlabel('Time (s)')
00103 ylabel('Altitude sea level (m)')
00104 title('Altitude x Time')
00105 grid(True)
00106
00107 setp(getp(gca(), 'xticklabels'), fontsize='x-small')
00108 setp(getp(gca(), 'yticklabels'), fontsize='x-small')
00109
00110 plt.tight_layout()
00111 pdf.savefig()
00112 close()
00113
00114
00115
00116 def altitudeTravDistPlot(self, pdf, dataTravDist, dataZ):
00117 rospy.loginfo('<<< Plot Altitude x Trav Dist >>>')
00118
00119 figure(figsize=(6,6))
00120
00121 fig = plt.figure()
00122 ax = fig.add_subplot(111)
00123
00124 plot(dataTravDist, dataZ)
00125
00126 xlabel('Distance (m)')
00127 ylabel('Altitude sea level (m)')
00128 title('Altitude x Travelled Distance')
00129 grid(True)
00130
00131 setp(getp(gca(), 'xticklabels'), fontsize='x-small')
00132 setp(getp(gca(), 'yticklabels'), fontsize='x-small')
00133
00134 plt.tight_layout()
00135 pdf.savefig()
00136 close()
00137
00138
00139
00140 def getXYLimits(self):
00141 [ODminX, ODmaxX] = self.dataOdom.getRangeDataX()
00142 rospy.loginfo("ODOM MinX={0} MaxX={1}".format(ODminX, ODmaxX))
00143 [ODminY, ODmaxY] = self.dataOdom.getRangeDataY()
00144 rospy.loginfo("ODOM MinY={0} MaxY={1}".format(ODminY, ODmaxY))
00145 return [ODminX, ODmaxX, ODminY, ODmaxY]
00146
00147
00148
00149
00150 def plotXYTrajectory(self, pdf):
00151 rospy.loginfo('<<< Plot XY Trajectory >>>')
00152
00153 figure(figsize=(6,6))
00154
00155 fig = plt.figure()
00156 ax = fig.add_subplot(111)
00157
00158
00159
00160
00161
00162 [minX, maxX, minY, maxY] = self.getXYLimits()
00163 rangeX = maxX - minX + 500
00164 rangeY = maxY - minY + 500
00165 if (rangeX < rangeY):
00166 rangeX = rangeY
00167 if (rangeY < rangeX):
00168 rangeY = rangeX
00169
00170 centerX = (maxX + minX) / 2.0
00171 centerY = (maxY + minY) / 2.0
00172
00173 rospy.loginfo("Center: X={0} Y={1} / Range: X={2} Y={3}".format(centerX, centerY, rangeX, rangeY))
00174
00175
00176 spacing = 20.0
00177 if (rangeX > 10000.0):
00178 spacing = 100.0
00179 if (rangeX > 30000.0):
00180 spacing = 200.0
00181
00182
00183 rospy.loginfo("[PlotsGenerator] Adding executed path...")
00184 plot(self.dataOdom.dataX, self.dataOdom.dataY, '-', lw=1, color='blue')
00185
00186
00187 for i in range(len(self.dataOdom.markerPointTime)):
00188 t = int(self.dataOdom.markerPointTime[i])
00189 if ((t % 50) == 0):
00190 rospy.loginfo("Add time marker: {0}".format(t))
00191 label = self.dataOdom.markerLabelStr[i]
00192 x = self.dataOdom.markerPointX[i]
00193 y = self.dataOdom.markerPointY[i]
00194 xtxt = 35 * math.cos(self.dataOdom.markerPointHeading[i])
00195 ytxt = 35 * math.sin(self.dataOdom.markerPointHeading[i])
00196 annotate(label, xy = (x, y), xytext = (xtxt, ytxt), size = 5,
00197 textcoords = 'offset points', ha = 'right', va = 'bottom',
00198 bbox = dict(boxstyle = 'round,pad=0.5', fc = 'yellow', alpha = 0.5),
00199 arrowprops = dict(arrowstyle = '->', connectionstyle = 'arc3,rad=0'))
00200
00201
00202 xlabel('EAST (m)')
00203 ylabel('NORTH (m)')
00204 title('Mission path')
00205
00206 axes().set_aspect('equal', 'datalim')
00207
00208 xticklabels = getp(gca(), 'xticklabels')
00209 yticklabels = getp(gca(), 'yticklabels')
00210 setp(yticklabels, fontsize='x-small')
00211 setp(xticklabels, fontsize='x-small')
00212
00213
00214 if (self.dataOdom.initTime != None):
00215 sttime = time.gmtime(int(self.dataOdom.initTime))
00216 timeStr = time.strftime("%a, %d %b %Y %H:%M:%S GMT", sttime)
00217 plt.figtext(0.70, 0.20, timeStr, bbox=dict(facecolor='yellow', alpha=0.75), size='xx-small')
00218
00219
00220 txtPosX = 0.12
00221 txtPosY = 0.90
00222 plt.figtext(txtPosX, txtPosY, "Executed trajectory", bbox=dict(facecolor='white', alpha=1.0), size='xx-small', color='blue')
00223
00224 originCoord = 'Origin Coordinates: {0} E / {1} N'.format(self.dataOdom.iniPosY, self.dataOdom.iniPosX)
00225 plt.figtext(0.2, 0.01, originCoord, bbox=dict(facecolor='gray', alpha=0.5), size='xx-small')
00226
00227
00228 plt.axis((centerX-rangeX/2, centerX+rangeX/2, centerY-rangeY/2, centerY+rangeY/2))
00229
00230 plt.tight_layout()
00231 pdf.savefig()
00232 close()
00233
00234
00235
00236
00237
00238 def finish(self, filename):
00239 rospy.loginfo("[PlotsGenerator] finish({0})".format(filename))
00240
00241
00242 pdf = PdfPages(filename)
00243
00244
00245
00246
00247 self.plotXYTrajectory(pdf)
00248
00249
00250
00251 self.altitudeTimePlot(pdf, self.dataOdom.dataTime, self.dataOdom.dataZ)
00252
00253
00254
00255 self.altitudeTravDistPlot(pdf, self.dataOdom.dataTravDist, self.dataOdom.dataZ)
00256
00257
00258
00259 self.threePlotsOnePage(pdf, 'Velocity x Time', 'X axis (m/s)', 'Y axis (m/s)', 'Z axis (m/s)', 'time (s)',
00260 self.dataOdom.dataTime, self.dataOdom.dataVx, self.dataOdom.dataVy, self.dataOdom.dataVz)
00261
00262
00263
00264 self.threePlotsOnePage(pdf, 'Attitude x Time', 'Roll (degrees)', 'Pitch (degrees)', 'Yaw (degrees)', 'time (s)',
00265 self.dataOdom.dataTime, self.dataOdom.dataR, self.dataOdom.dataP, self.dataOdom.dataH)
00266
00267
00268
00269 self.threePlotsOnePage(pdf, 'Angular Speed x Time', 'Roll (degrees/s)', 'Pitch (degrees/s)', 'Yaw (degrees/s)', 'time (s)',
00270 self.dataOdom.dataTime, self.dataOdom.dataVr, self.dataOdom.dataVp, self.dataOdom.dataVh)
00271
00272
00273 d = pdf.infodict()
00274 d['Title'] = 'Odometry Plots PDF'
00275 d['Author'] = 'Silvio Maeta - smaeta@andrew.cmu.edu'
00276 d['Subject'] = 'Odometry data report plots - PDF formate file'
00277 d['Keywords'] = 'odometry plots'
00278 d['CreationDate'] = datetime.datetime.today()
00279 d['ModDate'] = datetime.datetime.today()
00280
00281
00282 pdf.close()
00283
00284
00285
00286
00287 if __name__ == '__main__':
00288
00289 rospy.init_node('generate_plots')
00290
00291 plotsGen = None
00292 subPose = None
00293
00294
00295 reportOutputFilename = rospy.get_param('/generate_plots/output_filename')
00296 pose_topic = rospy.get_param('/generate_plots/pose_topic')
00297
00298 try:
00299
00300 plotsGen = PlotsGenerator()
00301
00302
00303 subPose = rospy.Subscriber(pose_topic, Odometry, plotsGen.dataOdom.odometryHandler)
00304
00305
00306 r = rospy.Rate(5.0)
00307 while (not rospy.is_shutdown()):
00308 r.sleep()
00309
00310
00311 subPose.unregister()
00312
00313
00314 plotsGen.finish(reportOutputFilename)
00315 plotsGen = None
00316
00317 except rospy.ROSInterruptException:
00318 if (subPose != None):
00319 subPose.unregister()
00320 if (plotsGen != None):
00321 plotsGen.finish(reportOutputFilename)
00322 plotsGen = None
00323
00324
00325