00001 
00002 
00003 
00004 
00005 
00006 
00007 
00008 
00009 
00010 
00011 PKG_NAME = 'art_pilot'
00012 
00013 
00014 import sys
00015 import getopt
00016 import os
00017 import threading
00018 
00019 
00020 import roslib;
00021 roslib.load_manifest(PKG_NAME)
00022 import rospy
00023 
00024 
00025 from nav_msgs.msg import Odometry
00026 from art_msgs.msg import BrakeCommand
00027 from art_msgs.msg import BrakeState
00028 from art_msgs.msg import CarCommand
00029 from art_msgs.msg import CarDriveStamped
00030 from art_msgs.msg import ThrottleCommand
00031 from art_msgs.msg import ThrottleState
00032 
00033 import plot_speed                       
00034 
00035 class commandThread(threading.Thread):
00036     "Separate thread for shell commands."
00037 
00038     def __init__(self, command):
00039         "Shell command thread initialization."
00040         self.command = command
00041         threading.Thread.__init__(self)
00042 
00043     def run(self):
00044         "Run a shell command in this thread."
00045         rc = os.system(self.command)
00046         rospy.signal_shutdown('bag finished')
00047         return rc
00048 
00049 class speedTopics:
00050     "Monitor ROS speed topics for data analysis."
00051 
00052     def __init__(self, name=None):
00053         "Constructor method."
00054 
00055         
00056         if name:
00057             self.name = name
00058         else:
00059             self.name = 'speed'
00060         
00061         self.plt = plot_speed.speedData()
00062 
00063     def get_pilot_drive(self, cmd):
00064         "ROS callback for /pilot/drive topic."
00065         self.plt.set_pilot_cmd(cmd.header.stamp.to_sec(),
00066                                cmd.control.speed)
00067 
00068     def get_pilot_cmd(self, cmd):
00069         "ROS callback for /pilot/cmd topic."
00070         self.plt.set_pilot_cmd(cmd.header.stamp.to_sec(),
00071                                cmd.control.velocity)
00072 
00073     def get_odometry(self, odom):
00074         "ROS callback for /odom topic."
00075         if odom.header.stamp.to_sec() != 0.0:
00076             self.plt.set_odometry(odom.header.stamp.to_sec(),
00077                                   odom.twist.twist.linear.x)
00078 
00079     def get_brake_cmd(self, cmd):
00080         "ROS callback for /brake/cmd topic."
00081         self.plt.set_brake_cmd(cmd.header.stamp.to_sec(), cmd.position)
00082 
00083     def get_brake_state(self, state):
00084         "ROS callback for /brake/state topic."
00085         self.plt.set_brake_state(state.header.stamp.to_sec(), state.position)
00086 
00087     def get_throttle_cmd(self, cmd):
00088         "ROS callback for /throttle/cmd topic."
00089         self.plt.set_throttle_cmd(cmd.header.stamp.to_sec(), cmd.position)
00090 
00091     def get_throttle_state(self, state):
00092         "ROS callback for /throttle/state topic."
00093         self.plt.set_throttle_state(state.header.stamp.to_sec(), state.position)
00094 
00095     def get_bag(self, filename):
00096         "Acquire speed topic data from ROS bag."
00097         filename = os.path.expanduser(filename)
00098         self.name, fileext = os.path.splitext(os.path.basename(filename))
00099         commandThread('rosplay -a ' + filename).start()
00100         self.get_data(False)
00101 
00102     def get_data(self, verbose=True):
00103         "Acquire speed topic data until ROS shutdown."
00104         rospy.Subscriber('pilot/drive', CarDriveStamped, self.get_pilot_drive)
00105         rospy.Subscriber('pilot/cmd', CarCommand, self.get_pilot_cmd)
00106         rospy.Subscriber('odom', Odometry, self.get_odometry)
00107         rospy.Subscriber('brake/cmd', BrakeCommand, self.get_brake_cmd)
00108         rospy.Subscriber('brake/state', BrakeState, self.get_brake_state)
00109         rospy.Subscriber('throttle/cmd', ThrottleCommand, self.get_throttle_cmd)
00110         rospy.Subscriber('throttle/state', ThrottleState,
00111                          self.get_throttle_state)
00112 
00113         rospy.init_node('rosspeed')
00114         if verbose:
00115             print 'begin acquiring speed data -- interrupt when finished'
00116         try:
00117             rospy.spin()           
00118         except rospy.ROSInterruptException: pass
00119         if verbose:
00120             print 'done acquiring speed data'
00121 
00122     def plot(self, save=False, plotall=False):
00123         """ Plot some interesting data from the speed test run.
00124 
00125         When save=True write the figures to PNG files, otherwise show
00126         them interactively.
00127         """
00128         self.plt.name = self.name       
00129         if plotall:
00130             self.plt.plot(save)
00131         else:
00132             self.plt.plot_summary(save)
00133         
00134 
00135 b = speedTopics()
00136 
00137 def usage(progname):
00138     "Print usage message."
00139     print "\n", progname, """[-h] [ <file.bag> ]
00140 
00141  -a, --all         generate all available plots (default: just position)
00142  -h, --help        print this message
00143  -i, --interactive display plots to terminal (default: save as files)
00144 
00145  <file.bag>\tname of ROS bag file to analyze
00146 
00147 If a bag file is specified, read speed topics from it, saving plots of
00148 the data.  Otherwise, read the ROS topics directly from the running
00149 system.
00150  """
00151 
00152 
00153 def main(argv=None):
00154     "Main program, called as a script or interactively."
00155 
00156     if argv is None:
00157         argv = sys.argv                 
00158     argv = rospy.myargv(argv)           
00159 
00160     
00161     progname = os.path.basename(argv[0])
00162     if progname is "":
00163         progname = "rosspeed.py"
00164 
00165     
00166     try:
00167         opts, files = getopt.gnu_getopt(argv[1:], 'ahi',
00168                                         ('all', 'help', 'interactive'))
00169     except getopt.error, msg:
00170         print msg
00171         print "for help use --help"
00172         return 9
00173 
00174     plotall = False
00175     save = True
00176 
00177     for k,v in opts:
00178         if k in ("-a", "--all"):
00179             plotall = True
00180         if k in ("-h", "--help"):
00181             usage(progname)
00182             return 2
00183         if k in ("-i", "--interactive"):
00184             save = False
00185 
00186     if len(files) < 1:
00187         print "no bag file, reading speed topics directly"
00188         b.get_data()
00189         b.plot(save, plotall)
00190 
00191     elif len(files) == 1:
00192         print "Analyzing " + files[0]
00193         b.get_bag(files[0])
00194         b.plot(save, plotall)
00195 
00196     else:
00197         print "only one ROS bag file can be processed at a time"
00198         usage(progname)
00199         return 9
00200 
00201     return 0
00202 
00203 
00204 if __name__ == "__main__":
00205     
00206     sys.exit(main())