joint_state_viz.py
Go to the documentation of this file.
00001 #!/usr/bin/env python
00002 
00003 import matplotlib
00004 matplotlib.interactive( True )
00005 matplotlib.use( 'WXAgg' )
00006 
00007 import numpy as np
00008 import wx
00009 import sys
00010 
00011 import roslib
00012 roslib.load_manifest( 'rospy' )
00013 roslib.load_manifest( 'sensor_msgs' )
00014 roslib.load_manifest( 'std_msgs' )
00015 
00016 
00017 import rospy
00018 from sensor_msgs.msg import JointState
00019 from std_msgs.msg import Int8
00020 
00021 from threading import Thread, Lock
00022 
00023 class WXMatPlotLibPanel( wx.Panel ):
00024     def __init__( self, parent, color=None, dpi=None, **kwargs ):
00025         from matplotlib.backends.backend_wxagg import FigureCanvasWxAgg
00026         from matplotlib.figure import Figure
00027 
00028         # initialize Panel
00029         if 'id' not in kwargs.keys():
00030             kwargs['id'] = wx.ID_ANY
00031         if 'style' not in kwargs.keys():
00032             kwargs['style'] = wx.NO_FULL_REPAINT_ON_RESIZE
00033         wx.Panel.__init__( self, parent, **kwargs )
00034 
00035         # initialize matplotlib stuff
00036         self.figure = Figure( None, dpi )
00037         self.canvas = FigureCanvasWxAgg( self, -1, self.figure )
00038         #self.SetColor( color )
00039 
00040         self._SetSize()
00041         self.draw()
00042 
00043         self._resizeflag = False
00044 
00045         self.Bind(wx.EVT_IDLE, self._onIdle)
00046         self.Bind(wx.EVT_SIZE, self._onSize)
00047 
00048     def SetColor( self, rgbtuple=None ):
00049         """Set figure and canvas colours to be the same."""
00050         if rgbtuple is None:
00051             rgbtuple = wx.SystemSettings.GetColour( wx.SYS_COLOUR_BTNFACE ).Get()
00052         clr = [c/255. for c in rgbtuple]
00053         self.figure.set_facecolor( clr )
00054         self.figure.set_edgecolor( clr )
00055         self.canvas.SetBackgroundColour( wx.Colour( *rgbtuple ) )
00056 
00057     def _onSize( self, event ):
00058         self._resizeflag = True
00059 
00060     def _onIdle( self, evt ):
00061         if self._resizeflag:
00062             self._resizeflag = False
00063             self._SetSize()
00064 
00065     def _SetSize( self ):
00066         pixels = tuple( self.parent.GetClientSize() )
00067         self.SetSize( pixels )
00068         self.canvas.SetSize( pixels )
00069         self.figure.set_size_inches( float( pixels[0] )/self.figure.get_dpi(),
00070                                      float( pixels[1] )/self.figure.get_dpi() )
00071 
00072     def draw(self): pass # abstract, to be overridden by child classes
00073 
00074 class JointStateVizPanel( WXMatPlotLibPanel ):
00075     def __init__( self, parent, **kwargs ):
00076         self.lock = Lock()
00077         self.parent = parent
00078         self.positions = None
00079         self.velocities = None
00080         self.efforts = None
00081         WXMatPlotLibPanel.__init__( self, parent, **kwargs )
00082         #self.SetColor( (255,255,255) )
00083 
00084     def init_plots( self, names, limits ):
00085         N = len( names )
00086         self.axes = []
00087         self.lines = []
00088         self.scatter = []
00089         for j in range( N ):
00090             axes = self.figure.add_subplot( 3, N, j + 1 )
00091             axes.set_title( names[j] )
00092             upper = -np.pi
00093             lower = np.pi
00094 
00095             if limits[j].has_key( 'upper' ):
00096                 upper = limits[j].get( 'upper' )
00097 
00098             if limits[j].has_key( 'lower' ):
00099                 lower = limits[j].get( 'lower' )
00100 
00101             axes.set_ylim( lower, upper )
00102             axes.set_xticks( [] )
00103 
00104             self.lines.append( axes.plot( [0], 'r' )[0] )
00105 
00106             axes.autoscale_view( scalex = False, scaley = False )
00107 
00108             self.axes.append( axes )
00109 
00110         for j in range( N ):
00111             axes = self.figure.add_subplot( 3, N, j + N + 1 )
00112             effort = 30
00113 
00114             if limits[j].has_key( 'effort' ):
00115                 effort = limits[j].get( 'effort' )
00116 
00117             axes.set_ylim( -effort, effort )
00118             axes.set_xticks( [] )
00119 
00120             self.lines.append( axes.plot( [0], 'b' )[0] )
00121 
00122             self.axes.append( axes )
00123 
00124         for j in range( N ):
00125             axes = self.figure.add_subplot( 3, N, j + 2 * N + 1 )
00126             upper = -2 * np.pi
00127             lower = 2 * np.pi
00128             velocity = 2 * np.pi
00129 
00130             if limits[j].has_key( 'upper' ):
00131                 upper = limits[j].get( 'upper' )
00132 
00133             if limits[j].has_key( 'lower' ):
00134                 lower = limits[j].get( 'lower' )
00135 
00136             if limits[j].has_key( 'velocity' ):
00137                 velocity = limits[j].get( 'velocity' )
00138 
00139             axes.set_ylim( -velocity, velocity )
00140             axes.set_xlim( lower, upper )
00141 
00142             self.scatter.append( axes.scatter( [0], [0], 
00143                                                c = 'b',
00144                                                s = 2.0,
00145                                                marker = 'x') )
00146 
00147             self.axes.append( axes )
00148 
00149 
00150         #self.figure.subplots_adjust( wspace = 0.3, hspace = 0.1 )
00151 
00152     def update_plots( self ):
00153         # self.lock.acquire()
00154         
00155         if not hasattr( self, 'axes' ):  
00156             return
00157             
00158         if self.positions is None or len( self.positions ) == 0:
00159             return
00160 
00161         ( l, N ) = self.positions.shape
00162 
00163         for j in range( N ):
00164             axes = self.axes[j]
00165             axes.lines[0].remove()
00166             axes.plot( self.positions[:,j], 'r')
00167             
00168         for j in range( N ):
00169             axes = self.axes[j + N]
00170             axes.lines[0].remove()
00171             axes.plot( self.efforts[:,j], 'b')
00172 
00173 
00174         for j in range( N ):
00175             axes = self.axes[j + N * 2]
00176             self.scatter[j].remove()
00177             self.scatter[j] = axes.scatter( self.positions[:,j], 
00178                           self.velocities[:,j],
00179                           c = 'b',
00180                           s = 2.0,
00181                           marker = 'x')
00182 
00183         # self.lock.release()
00184 
00185     def draw( self ):
00186         self.update_plots()
00187 
00188     def setData( self, pos, vel, eff, duration ):
00189         self.positions = pos
00190         self.velocities = vel
00191         self.efforts = eff
00192         self.duration = duration
00193         self.draw()
00194 
00195 class JointStateVizFrame( wx.Frame ) :
00196     def __init__( self, title, ns, js_topic ):
00197         wx.Frame.__init__( self, None, wx.ID_ANY, title, size = (2000, 800) )
00198         self.CreateStatusBar()
00199         self.SetStatusText( 'waiting for data on %s ...'%js_topic )
00200         self.panel = JointStateVizPanel( self )
00201         self.Show()
00202 
00203         self.js_sub = rospy.Subscriber( js_topic, JointState, self.js_callback )
00204         self.update_sub = rospy.Subscriber( ''.join( (ns, '/update' ) ), Int8, self.update_callback )
00205 
00206         # load parameters
00207         (self.joint_names, self.limits) = self.load_params( ns )
00208 
00209         self.idx = None
00210         self.joint_states = []
00211 
00212         self.panel.init_plots( self.joint_names, self.limits )
00213     
00214     def load_params( self, ns ):
00215         params = rospy.get_param( ns )
00216         joint_names = params.keys()
00217 
00218         limits = []
00219         for joint_name in joint_names:
00220             limits.append( params.get( joint_name ) )
00221 
00222         return ( joint_names, limits )
00223 
00224     def js_callback( self, msg ):
00225         self.joint_states.append( msg )
00226 
00227     def update_callback( self, msg ):
00228         if msg.data == 0:
00229             self.joint_states = []
00230         elif msg.data == 1:
00231             self.update()
00232 
00233     def update( self ):
00234         if self.joint_names is None or len( self.joint_names ) == 0 or len( self.joint_states ) == 0:
00235             return
00236         if self.idx is None:
00237             self.idx = map( self.joint_states[0].name.index, self.joint_names )
00238 
00239         positions = []
00240         velocities = []
00241         efforts = []
00242 
00243         for js in self.joint_states:
00244             pos =  map( lambda x: js.position[x], self.idx )
00245             vel = map( lambda x: js.velocity[x], self.idx )
00246             effort = map( lambda x: js.effort[x], self.idx )
00247             positions.append( pos )
00248             velocities.append( vel )
00249             efforts.append( effort )
00250 
00251         start_time = self.joint_states[0].header.stamp
00252         stop_time = self.joint_states[-1].header.stamp
00253         duration = stop_time - start_time
00254 
00255         self.panel.setData( np.asarray( positions ), 
00256                             np.asarray( velocities ), 
00257                             np.asarray( efforts ),
00258                             duration.to_sec())
00259 
00260         # status = ''.join( ( str( self.joint_states[0].header.stamp ),
00261         #                     ' ',
00262         #                     str( duration.to_sec() ) ) )
00263         
00264         status = 'ros-time: %s, duration: %5.3f sec'%( self.joint_states[0].header.stamp, duration.to_sec() )
00265         
00266         self.SetStatusText( status ) 
00267 
00268         self.joint_states = []
00269 
00270 
00271 
00272 
00273 arm_joint_names = ['lr_shoulder_pan_joint',
00274                    'lr_shoulder_lift_joint',
00275                    'lr_upper_arm_roll_joint',
00276                    'lr_elbow_flex_joint',
00277                    'lr_forearm_roll_joint',
00278                    'lr_wrist_flex_joint',
00279                    'lr_wrist_roll_joint']
00280 
00281 l_arm_joint_names = map(lambda s: s.replace('lr_', 'l_'), arm_joint_names )
00282 r_arm_joint_names = map(lambda s: s.replace('lr_', 'r_'), arm_joint_names )
00283 
00284 
00285 if __name__ == '__main__':
00286     rospy.init_node( 'joint_state_viz_node' )
00287     app = wx.PySimpleApp( 0 )
00288     frame = JointStateVizFrame( 'Joint-State-Viz', '/joint_state_viz', '/joint_states' )
00289     app.MainLoop()
00290     
00291 
00292 
00293     


kelsey_sandbox
Author(s): kelsey
autogenerated on Wed Nov 27 2013 11:52:04