generate_plots.py
Go to the documentation of this file.
00001 #!/usr/bin/env python
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         # 1st plot
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         # 2nd plot
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         # 3rd plot
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() # note the format='pdf' argument!
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() # note the format='pdf' argument!
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() # note the format='pdf' argument!
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     #PLOT XY TRAJECTORY
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         #adjust limits to focus on trajectory / waypoints
00159         #find range in X and Y
00160         #equalize both ranges
00161         #calculate new center
00162         [minX, maxX, minY, maxY] = self.getXYLimits() #use odometry
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         # get coordinates to plot altitude map
00176         spacing  = 20.0
00177         if (rangeX > 10000.0):
00178             spacing = 100.0
00179         if (rangeX > 30000.0):
00180             spacing = 200.0
00181             
00182         #Add executed path
00183         rospy.loginfo("[PlotsGenerator] Adding executed path...")
00184         plot(self.dataOdom.dataX, self.dataOdom.dataY, '-', lw=1, color='blue')
00185 
00186         #Add time markers along trajectory - every 50 seconds
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         #Add plot labels
00202         xlabel('EAST (m)')
00203         ylabel('NORTH (m)')
00204         title('Mission path')
00205         #grid(True)
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         #Add legends explaining plotted lines
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         #set plot area limits
00228         plt.axis((centerX-rangeX/2, centerX+rangeX/2, centerY-rangeY/2, centerY+rangeY/2))
00229 
00230         plt.tight_layout()
00231         pdf.savefig() # note the format='pdf' argument!
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         #PLOT MISSION (2D top down view)
00247         self.plotXYTrajectory(pdf)
00248 
00249         #-----------------------------------------------------------------------
00250         #PLOT ALTITUDE vs TIME
00251         self.altitudeTimePlot(pdf, self.dataOdom.dataTime, self.dataOdom.dataZ)
00252 
00253         #-----------------------------------------------------------------------
00254         #PLOT ALTITUDE vs TRAV DISTANCE
00255         self.altitudeTravDistPlot(pdf, self.dataOdom.dataTravDist, self.dataOdom.dataZ)
00256 
00257         #-----------------------------------------------------------------------
00258         #PLOT LINEAR VELOCITIES
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         #PLOT ATTITUDE
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         #PLOT ANGULAR VELOCITIES
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         # Remember to close the object - otherwise the file will not be usable
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     #load parameters - output file name and odometry topic name
00295     reportOutputFilename = rospy.get_param('/generate_plots/output_filename')
00296     pose_topic = rospy.get_param('/generate_plots/pose_topic')
00297 
00298     try:
00299         #Get mission information and build plot file
00300         plotsGen = PlotsGenerator()
00301 
00302         #Associate subscribers with proper data handlers                
00303         subPose = rospy.Subscriber(pose_topic, Odometry, plotsGen.dataOdom.odometryHandler)
00304             
00305         #Collect information loop
00306         r = rospy.Rate(5.0)
00307         while (not rospy.is_shutdown()):
00308             r.sleep()
00309                                 
00310         #unregister subscribers before writing to file
00311         subPose.unregister()
00312         
00313         #Finish processing and generate plot file
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 


plot_util
Author(s):
autogenerated on Thu Jun 6 2019 18:18:33