$search
00001 #!/usr/bin/env python 00002 # Software License Agreement (BSD License) 00003 # 00004 # Copyright (c) 2008, Willow Garage, Inc. 00005 # All rights reserved. 00006 # 00007 # Redistribution and use in source and binary forms, with or without 00008 # modification, are permitted provided that the following conditions 00009 # are met: 00010 # 00011 # * Redistributions of source code must retain the above copyright 00012 # notice, this list of conditions and the following disclaimer. 00013 # * Redistributions in binary form must reproduce the above 00014 # copyright notice, this list of conditions and the following 00015 # disclaimer in the documentation and/or other materials provided 00016 # with the distribution. 00017 # * Neither the name of the Willow Garage nor the names of its 00018 # contributors may be used to endorse or promote products derived 00019 # from this software without specific prior written permission. 00020 # 00021 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 00022 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 00023 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 00024 # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 00025 # COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 00026 # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 00027 # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 00028 # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 00029 # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 00030 # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 00031 # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 00032 # POSSIBILITY OF SUCH DAMAGE. 00033 # 00034 00035 PKG = 'fingertip_pressure' 00036 00037 import roslib 00038 roslib.load_manifest(PKG) 00039 00040 import sys 00041 import rospy 00042 from pr2_msgs.msg import PressureState 00043 import math 00044 00045 from fingertip_pressure.colormap import color255 00046 from fingertip_pressure.msg import PressureInfo 00047 from geometry_msgs.msg import Vector3 00048 00049 import wxversion 00050 wxversion.ensureMinimal("2.8") 00051 00052 import wx 00053 import threading 00054 from wx import xrc 00055 00056 NUMSENSORS = 22 00057 RATE = 5. #Hz 00058 00059 def txtcolor(data): 00060 (r,g,b)=color255(data) 00061 if r + g + b < 3 *128: 00062 (rt,gt,bt) = (255,255,255) 00063 else: 00064 (rt,gt,bt) = (0,0,0) 00065 return ("#%02x%02x%02x"%(r,g,b),"#%02x%02x%02x"%(rt,gt,bt)) 00066 00067 class GripperPressurePanel(wx.Panel): 00068 def __init__(self, parent, topic): 00069 wx.Panel.__init__(self, parent, wx.ID_ANY) 00070 00071 # Set up UI 00072 sizer = wx.BoxSizer(wx.HORIZONTAL) 00073 self.panel0 = FingertipPressurePanel(self) 00074 self.panel1 = FingertipPressurePanel(self) 00075 sizer.Add(self.panel0.panel, 1, wx.EXPAND) 00076 sizer.AddSpacer(5) 00077 sizer.Add(self.panel1.panel, 1, wx.EXPAND) 00078 self.SetSizer(sizer) 00079 00080 # Set up subscription 00081 self._mutex = threading.Lock() 00082 self.new_message_ = None 00083 self.new_info_ = None 00084 rospy.Subscriber(topic, PressureState, self.message_callback) 00085 rospy.Subscriber(topic+"_info", PressureInfo, self.info_callback) 00086 00087 self.timer = wx.Timer(self, 1) 00088 self.Bind(wx.EVT_TIMER, self.on_timer, self.timer) 00089 00090 def info_callback(self, message): 00091 self._mutex.acquire() 00092 self.new_info_ = message 00093 self._mutex.release() 00094 00095 def message_callback(self, message): 00096 #print 'message_callback' 00097 self._mutex.acquire() 00098 00099 self.new_message_ = message 00100 00101 if not self.timer.IsRunning(): 00102 self.timer.Start(1000./RATE, True) 00103 wx.CallAfter(self.display) 00104 00105 self._mutex.release() 00106 00107 def on_timer(self, event): 00108 #print 'timer' 00109 pass 00110 00111 def display(self): 00112 self._mutex.acquire() 00113 00114 if self.new_message_ != None: 00115 #print 'newmsg' 00116 00117 self.panel0.new_message(self.new_message_.l_finger_tip) 00118 self.panel1.new_message(self.new_message_.r_finger_tip) 00119 00120 self.new_message_ = None 00121 00122 self.Refresh() 00123 00124 if self.new_info_ != None: 00125 self.panel0.set_info(self.new_info_.sensor[0]) 00126 self.panel1.set_info(self.new_info_.sensor[1]) 00127 self.new_info_ = None 00128 self.Refresh() 00129 00130 self._mutex.release() 00131 00132 class FingertipPressurePanel: 00133 Newton = 'N'; 00134 kPascal = 'kPa'; 00135 00136 def __init__(self, parent): 00137 self._mutex = threading.Lock() 00138 xrc_path = roslib.packages.get_pkg_dir(PKG) + '/ui/fingertip_panel.xrc' 00139 panelxrc = xrc.XmlResource(xrc_path) 00140 00141 self.panel = panelxrc.LoadPanel(parent, 'FingertipPressurePanel') 00142 00143 bag =self.panel.GetSizer() 00144 bag.SetEmptyCellSize(wx.Size(0,0)) 00145 00146 self.scalings = None 00147 self.zeros = [0 for i in range(0,22)] 00148 self.recentmean = [0 for i in range(0,22)] 00149 00150 self.pad = [] 00151 for i in range(0, NUMSENSORS): 00152 self.pad.append(xrc.XRCCTRL(self.panel, 'pad%i'%i)) 00153 self.pad[i].SetEditable(False) 00154 font = self.pad[i].GetFont() 00155 font.SetPointSize(6) 00156 self.pad[i].SetFont(font) 00157 self.pad[i].SetMinSize(wx.Size(40,35)) 00158 self.frame_id_box = xrc.XRCCTRL(self.panel, 'frame_id') 00159 00160 self.panel.Bind(wx.EVT_RADIOBUTTON, self.set_Newton, id=xrc.XRCID('button_N')) 00161 self.panel.Bind(wx.EVT_RADIOBUTTON, self.set_kPascal, id=xrc.XRCID('button_kPa')) 00162 self.unit = self.Newton 00163 00164 self.panel.Bind(wx.EVT_CHECKBOX, self.set_Zero, id=xrc.XRCID('button_Zero')) 00165 00166 def set_Newton(self, event): 00167 self._mutex.acquire() 00168 self.unit = self.Newton 00169 self._mutex.release() 00170 00171 def set_kPascal(self, event): 00172 self._mutex.acquire() 00173 self.unit = self.kPascal 00174 self._mutex.release() 00175 00176 def set_Zero(self, event): 00177 self._mutex.acquire() 00178 cb = event.GetEventObject() 00179 if cb.IsChecked(): 00180 self.zeros = list(self.recentmean); 00181 else: 00182 self.zeros = [0 for i in range(0,22)] 00183 self._mutex.release() 00184 00185 def calc_area(self,u,v): 00186 w = Vector3() 00187 w.x = u.y * v.z - u.z * v.y 00188 w.y = u.z * v.x - u.x * v.z 00189 w.z = u.x * v.y - u.y * v.x 00190 return math.sqrt(w.x*w.x + w.y*w.y + w.z*w.z) 00191 00192 def set_info(self, info): 00193 self._mutex.acquire() 00194 self.scalings = info.force_per_unit 00195 self.areas = [self.calc_area(info.halfside1[i], info.halfside2[i]) * 4 for i in range(0,22)] 00196 self.frame_id_box.SetValue(info.frame_id) 00197 self._mutex.release() 00198 00199 def new_message(self, data): 00200 self._mutex.acquire() 00201 #print "FingertipPressurePanel new_message" 00202 for i in range(0, NUMSENSORS): 00203 #print repr(color(data[i])) 00204 #print txtcolor(data[i]) 00205 self.recentmean[i] = 0.8 * self.recentmean[i] + 0.2 * data[i] 00206 dat = data[i] - self.zeros[i] 00207 if self.scalings != None: 00208 if self.unit == self.kPascal: 00209 val = dat / self.scalings[i] / self.areas[i] / 1e3 00210 colval = val / 30. 00211 scaled = '%.0f'%val 00212 else: 00213 val = dat / self.scalings[i] 00214 colval = val / 3. 00215 scaled = '%.2f'%val 00216 else: 00217 val = dat 00218 colval = val / 6000. 00219 scaled = '??' 00220 (colb,colf)=txtcolor(colval) 00221 self.pad[i].SetBackgroundColour(colb) 00222 self.pad[i].SetForegroundColour(colf) 00223 self.pad[i].SetValue('#%i\n%i\n%s %s'%(i,dat,scaled,self.unit)) 00224 self._mutex.release() 00225