fingertip_qualification.py
Go to the documentation of this file.
00001 #!/usr/bin/env python
00002 # Copyright (c) 2009, Willow Garage, Inc.
00003 # All rights reserved.
00004 #
00005 # Redistribution and use in source and binary forms, with or without
00006 # modification, are permitted provided that the following conditions are met:
00007 #
00008 #     * Redistributions of source code must retain the above copyright
00009 #       notice, this list of conditions and the following disclaimer.
00010 #     * Redistributions in binary form must reproduce the above copyright
00011 #       notice, this list of conditions and the following disclaimer in the
00012 #       documentation and/or other materials provided with the distribution.
00013 #     * Neither the name of the Willow Garage, Inc. nor the names of its
00014 #       contributors may be used to endorse or promote products derived from
00015 #       this software without specific prior written permission.
00016 #
00017 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
00018 # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00019 # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00020 # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
00021 # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
00022 # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
00023 # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
00024 # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
00025 # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
00026 # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00027 # POSSIBILITY OF SUCH DAMAGE.
00028 
00029 ##\author Matthew Piccoli, Kevin Watts
00030 ##\brief Qualification of gripper tips
00031 ##
00032 ## This test checks that the gripper tip sensors on the PR2 gripper. It checks 
00033 ## that each tip has the correct number of tips, and that each one is reading.
00034 ## After that, the node commands the gripper to repeatedly open and close and measures
00035 ## the total force of the interior gripper sensors. It compares this total force to a
00036 ## cubic polynomial. After checking the relationship between total pressure and gripper 
00037 ## force, and checking the differences between the two gripper tips, the node reports
00038 ## success or failure.
00039 
00040 from __future__ import with_statement
00041 
00042 PKG = 'qualification'
00043 import roslib
00044 roslib.load_manifest(PKG)
00045 
00046 import numpy
00047 import matplotlib
00048 import matplotlib.pyplot as plot
00049 from StringIO import StringIO
00050 from time import sleep
00051 import threading
00052 import os
00053 
00054 import rospy
00055 from pr2_self_test_msgs.srv import TestResult, TestResultRequest
00056 from pr2_self_test_msgs.msg import Plot
00057 from std_msgs.msg import Float64
00058 from pr2_msgs.msg import PressureState
00059 
00060 lvl_dict = {0: 'OK', 1: 'Questionable', 2: 'Failure' }
00061 
00062 ##\brief Performs testing PR2 gripper tip sensors
00063 class FingertipQualification:
00064     def __init__(self):
00065         self._mutex = threading.Lock()
00066         self.set_cmd = 0.0
00067         
00068         self.pub = rospy.Publisher('r_gripper_effort_controller/command', Float64)
00069 
00070         self.l_finger_tip = None
00071         self.r_finger_tip = None
00072 
00073         rospy.init_node('fingertip_qualification')
00074 
00075         # Squeezing params
00076         self.initial = rospy.get_param('~grasp_force_initial', -25.0)
00077         self.increment = rospy.get_param('~grasp_force_increment', -25.0) 
00078         self.num_increments = rospy.get_param('~grasp_increments', 4) 
00079 
00080         # Equation to fit against
00081         self.x0 = rospy.get_param('~x^0', 0)
00082         self.x1 = rospy.get_param('~x^1', 0)
00083         self.x2 = rospy.get_param('~x^2', 0)
00084         self.x3 = rospy.get_param('~x^3', 0)
00085 
00086         # Gripper parameters
00087         self.fingertip_refresh = rospy.get_param('~fingertip_refresh_hz', 25)
00088         self.num_sensors = rospy.get_param('~num_sensors', 22)
00089         self.num_sensors_outside = rospy.get_param('~num_sensors_outside', 7)
00090         self.force = self.initial
00091 
00092         # Tolerances
00093         self._tol_max_quest = rospy.get_param('~tol_max_question', 10)
00094         self._tol_max_fail = rospy.get_param('~tol_max_fail', 20)
00095         self._tol_avg_quest = rospy.get_param('~tol_avg_question', 10)
00096         self._tol_avg_fail = rospy.get_param('~tol_avg_fail', 20)
00097 
00098         self._diff_max_quest = rospy.get_param('~diff_max_question', 5)
00099         self._diff_max_fail = rospy.get_param('~diff_max_fail', 10)
00100         self._diff_avg_quest = rospy.get_param('~diff_avg_question', 5)
00101         self._diff_avg_fail = rospy.get_param('~diff_avg_fail', 10)
00102         self._diff_avg_abs_quest = rospy.get_param('~diff_avg_abs_question', 5)
00103         self._diff_avg_abs_fail = rospy.get_param('~diff_avg_abs_fail', 10)
00104         
00105         # Don't look at tip values, just check the connections
00106         self.check_connect_only = rospy.get_param('~check_connect_only', False)
00107         self.expect_no_connect  = rospy.get_param('~not_connected', False)
00108 
00109         self.data_sent = False
00110         self.result_service = rospy.ServiceProxy('/test_result', TestResult)
00111 
00112         self._connection_data = ''
00113 
00114         # Data
00115         self._forces = []
00116         self._expected = []
00117         self._tip0 = []
00118         self._tip1 = []
00119 
00120         self._pressure_topic = 'pressure/r_gripper_motor'
00121         rospy.Subscriber(self._pressure_topic, PressureState, self.pressure_callback)
00122 
00123     ##\brief Callback for gripper pressure topic
00124     def pressure_callback(self, data):
00125         with self._mutex:
00126             self.l_finger_tip = data.l_finger_tip
00127             self.r_finger_tip = data.r_finger_tip
00128 
00129     ##\brief Record errors in analysis
00130     def test_failed_service_call(self, except_str = ''):
00131         rospy.logerr(except_str)
00132         r = TestResultRequest()
00133         r.html_result = except_str
00134         r.text_summary = 'Caught exception, automated test failure.'
00135         r.plots = []
00136         r.result = TestResultRequest.RESULT_FAIL
00137         self.send_results(r)
00138 
00139     ##\brief Send test results to qualification system
00140     def send_results(self, test_result):
00141         if self.data_sent:
00142             return 
00143 
00144         rospy.wait_for_service('test_result', 15)
00145         self.result_service.call(test_result)
00146         self.data_sent = True
00147 
00148     ##\brief Command open, wait for 1 sec
00149     def open_gripper(self):
00150         self.set_cmd = 50
00151         self.pub.publish(self.set_cmd)
00152         sleep(1)
00153         
00154     ##\brief Command close at desired force, wait for 4 sec
00155     def close_gripper(self):
00156         self.set_cmd = self.force
00157         self.pub.publish(self.set_cmd)
00158         sleep(4)
00159     
00160     ##\brief Make sure we have correct number of gripper sensors on each tip, and all are OK
00161     def check_connected(self):
00162         sleep(1/self.fingertip_refresh*2)
00163         with self._mutex:
00164             if self.l_finger_tip is None or self.r_finger_tip is None:
00165                 r = TestResultRequest()
00166                 r.text_summary = 'No gripper tip data.'
00167                 
00168                 r.html_result = '<p>No gripper tip data. Check connections. L tip OK: %s, R tip OK: %s.</p>\n' % (str(self.l_finger_tip is None), str(self.r_finger_tip is None))
00169                 r.html_result +=  '<hr size="2">\n' + self._write_equation()
00170                 r.html_result += '<hr size="2">\n' + self._write_params()
00171                 r.html_result += '<hr size="2">\n' + self._write_tols()
00172                 r.result = TestResultRequest.RESULT_FAIL
00173                 self.send_results(r)
00174 
00175             if len(self.l_finger_tip) != self.num_sensors or len(self.r_finger_tip) != self.num_sensors:
00176                 r = TestResultRequest()
00177                 r.text_summary = 'Incorrect number of sensors. Expected: %d.' % self.num_sensors
00178                 
00179                 r.html_result = '<p>Incorrect number of sensors. Expected: %d. L tip: %d, tip 1: %d.</p>\n' % (self.num_sensors, len(self.l_finger_tip), len(self.r_finger_tip))
00180                 r.html_result +=  '<hr size="2">\n' + self._write_equation()
00181                 r.html_result += '<hr size="2">\n' + self._write_params()
00182                 r.html_result += '<hr size="2">\n' + self._write_tols()
00183                 r.result = TestResultRequest.RESULT_FAIL
00184                 self.send_results(r)
00185 
00186             ok = True
00187             tips_bad = True
00188             connect_table = '<table border="1" cellpadding="2" cellspacing="0">\n'
00189             connect_table += '<tr><td><b>Sensor</b></td><td><b>L tip</b></td><td><b>R tip</b></td></tr>\n'
00190             for i in range(0, self.num_sensors):
00191                 tip0 = 'OK'
00192                 tip1 = 'OK'
00193                 if self.l_finger_tip[i] == 0 or self.l_finger_tip[i] == -1:
00194                     ok = False
00195                     tip0 = 'No data'  
00196                 else:
00197                     tips_bad = False
00198 
00199                 if self.r_finger_tip[i] == 0 or self.r_finger_tip[i] == -1:
00200                     ok = False
00201                     tip1 = 'No data'
00202                 else:
00203                     tips_bad = False
00204 
00205                 connect_table += '<tr><td>%d</td><td>%s</td><td>%s</td></tr>\n' % (i, tip0, tip1)
00206             connect_table += '</table>\n'
00207 
00208         connect_str = 'OK'
00209         if not ok:
00210             connect_str = 'Not connected'
00211         self._connected_data = '<p align=center><b>Tip connections: %s</b></p><br>\n' % connect_str
00212         self._connected_data += connect_table
00213         
00214         if self.expect_no_connect:
00215            r = TestResultRequest()
00216            
00217            r.html_result = self._connected_data 
00218            r.html_result += '<hr size="2">\n' + self._write_params()
00219            if tips_bad:
00220                r.text_summary = 'Gripper tips not connected - OK'
00221                r.result = TestResultRequest.RESULT_PASS
00222            else:
00223                r.text_summary = 'Gripper tips connected, expected no connection'
00224                r.result = TestResultRequest.RESULT_FAIL
00225            
00226            self.send_results(r)
00227            return tips_bad
00228         
00229         if self.check_connect_only:
00230             r = TestResultRequest()
00231 
00232             r.html_result = self._connected_data 
00233             r.html_result += '<hr size="2">\n' + self._write_params()
00234             if ok:
00235                 r.text_summary = 'Gripper tips connected'
00236                 r.result = TestResultRequest.RESULT_PASS
00237             else:
00238                 r.text_summary = 'Gripper tips not connected'
00239                 r.result = TestResultRequest.RESULT_FAIL
00240             self.send_results(r)
00241             return ok
00242 
00243         if not ok:
00244             r = TestResultRequest()
00245             r.text_summary = 'Not connected.'
00246             r.html_result = self._connected_data 
00247             r.html_result +=  '<hr size="2">\n' + self._write_equation()
00248             r.html_result += '<hr size="2">\n' + self._write_params()
00249             r.html_result += '<hr size="2">\n' + self._write_tols()
00250             r.result = TestResultRequest.RESULT_FAIL
00251             self.send_results(r)
00252                 
00253         return ok
00254 
00255     ##\brief Increment commanded force by increment
00256     def increment_value(self):
00257         self.force += self.increment
00258     
00259     ##\brief Record "zero" of gripper, when tips are open
00260     def record_zero_val(self):
00261         with self._mutex:
00262             self.starting_sum0 = 0
00263             self.starting_sum1 = 0
00264             for i in range(self.num_sensors_outside, self.num_sensors):
00265                 self.starting_sum0 += self.l_finger_tip[i]
00266                 self.starting_sum1 += self.r_finger_tip[i]
00267       
00268     ##\brief Record sum of gripper tip pressure at the commanded force
00269     def record_increase(self):
00270         with self._mutex:
00271             current_sum0 = 0
00272             current_sum1 = 0
00273             for i in range(self.num_sensors_outside, self.num_sensors):
00274                 current_sum0 += self.l_finger_tip[i]
00275                 
00276             for i in range(self.num_sensors_outside, self.num_sensors):
00277                 current_sum1 += self.r_finger_tip[i]
00278  
00279         expected_value = self.force*self.force*self.force*self.x3 + self.force*self.force*self.x2 + self.force*self.x1 + self.x0
00280 
00281         self._forces.append(self.force)
00282         self._expected.append(expected_value)
00283         self._tip0.append(current_sum0 - self.starting_sum0)
00284         self._tip1.append(current_sum1 - self.starting_sum1)
00285 
00286     ##\brief Write fit equation as HTML table
00287     def _write_equation(self):
00288         html = '<p align=center><b>Gripper Equation</b></p><br>\n'
00289         html += '<table border="1" cellpadding="2" cellspacing="0">\n'
00290         html += '<tr><td><b>Term</b></td><td><b>Value</b></td></tr>\n'
00291         html += '<tr><td>Force^3</td><td>%f</td></tr>\n' % self.x3
00292         html += '<tr><td>Force^2</td><td>%f</td></tr>\n' % self.x2
00293         html += '<tr><td>Force</td><td>%f</td></tr>\n' % self.x1
00294         html += '<tr><td>Constant</td><td>%s</td></tr>\n' % self.x0
00295         html += '</table>\n'
00296 
00297         return html
00298 
00299     ##\brief Write test params as HTML table
00300     def _write_params(self):
00301         html = '<p align=center><b>Test Parameters</b></p><br>\n'
00302         html += '<table border="1" cellpadding="2" cellspacing="0">\n'
00303         html += '<tr><td><b>Parameter</b></td><td><b>Value</b></td></tr>\n'
00304         html += '<tr><td>Pressure Topic</td><td>%s</td></tr>\n' % self._pressure_topic
00305         html += '<tr><td>Num Sensors</td><td>%d</td></tr>\n' % self.num_sensors
00306         html += '<tr><td>Num Sensors Outside</td><td>%d</td></tr>\n' % self.num_sensors_outside
00307         html += '<tr><td>Num. Increments</td><td>%d</td></tr>\n' % self.num_increments
00308         html += '<tr><td>Max Force</td><td>%f</td></tr>\n' % (self.force - self.increment)
00309         html += '<tr><td>Force Increment</td><td>%f</td></tr>\n' % self.increment
00310         html += '</table>\n'
00311 
00312         return html
00313 
00314     ##\brief Write tolerances as HTML table
00315     def _write_tols(self):
00316         html = '<p align=center><b>Error Tolerances</b></p>\n'
00317         html += '<p>All tolerances given as a percent of the maximum observed value.</p>\n'
00318         html += '<table border="1" cellpadding="2" cellspacing="0">\n'
00319         html += '<tr><td><b>Parameter</b></td><td><b>Questionable</b></td><td><b>Failure</b></td></tr>\n'
00320         html += '<tr><td>Max Error</td><td>%.1f</td><td>%.1f</td></tr>\n' % (self._tol_max_quest, self._tol_max_fail)
00321         html += '<tr><td>Average Error</td><td>%.1f</td><td>%.1f</td></tr>\n' % (self._tol_avg_quest, self._tol_avg_fail)
00322         html += '<tr><td>Max Diff.</td><td>%.1f</td><td>%.1f</td></tr>\n' % (self._diff_max_quest, self._diff_max_fail)
00323         html += '<tr><td>Avg. Diff.</td><td>%.1f</td><td>%.1f</td></tr>\n' % (self._diff_avg_quest, self._diff_avg_fail)
00324         html += '<tr><td>Avg. Abs. Diff.</td><td>%.1f</td><td>%.1f</td></tr>\n' % (self._diff_avg_abs_quest, self._diff_avg_abs_fail)
00325         
00326         html += '</table>\n'
00327 
00328         return html
00329 
00330     ##\brief Write pressure at each datapoint for both tips
00331     def _write_data(self):
00332         html = '<p align=center><b>Fingertip Pressure Data</b></p>\n'
00333         html += '<table border="1" cellpadding="2" cellspacing="0">\n'
00334         html += '<tr><td><b>Force</b></td><td><b>L tip</b></td><td><b>R tip</b></td><td><b>Expected</b></td></tr>\n'
00335         for i in range(0, len(self._forces)):
00336             html += '<tr><td>%.2f</td><td>%.2f</td><td>%.2f</td><td>%.2f</td></tr>\n' % (self._forces[i], self._tip0[i], self._tip1[i], self._expected[i])
00337         html += '</table>\n'
00338 
00339         # Write CSV log to allow oocalc graph
00340         if False:
00341             import csv
00342             csv_path = os.path.join(roslib.packages.get_pkg_dir('qualification'), 'results/temp/%s_fingers.csv' % rospy.get_param('/qual_item/serial', 'finger'))
00343             log_csv = csv.writer(open(csv_path, 'wb'))
00344             log_csv.writerow(['Force', 'L tip', 'R tip', 'Expected'])
00345             for i in range(0, len(self._forces)):
00346                 log_csv.writerow([self._forces[i], self._tip0[i], self._tip1[i], self._expected[i]])
00347             
00348             html += '<p>Wrote CSV of results to: %s.</p>\n' % csv_path
00349 
00350         return html
00351 
00352     ##\brief At every point, check differences bwt tips
00353     def _check_diff(self):
00354         diff = numpy.array(self._tip0) - numpy.array(self._tip1)
00355         avg_vals = 0.5 * (numpy.array(self._tip0) + numpy.array(self._tip1))
00356         
00357         max_val = max(avg_vals)
00358         max_diff = max(abs(diff)) / max_val * 100
00359         avg_diff = abs(numpy.average(diff) / max_val * 100)
00360         avg_abs_diff = numpy.average(abs(diff)) / max_val * 100
00361 
00362         max_diff_lvl = 0
00363         avg_diff_lvl = 0
00364         avg_abs_diff_lvl = 0
00365 
00366         if max_diff > self._diff_max_quest:
00367             max_diff_lvl = 1
00368         if max_diff > self._diff_max_fail:
00369             max_diff_lvl = 2
00370 
00371         if avg_diff > self._diff_avg_quest:
00372             avg_diff_lvl = 1
00373         if avg_diff > self._diff_avg_fail:
00374             avg_diff_lvl = 2
00375 
00376         if avg_abs_diff > self._diff_avg_abs_quest:
00377             avg_abs_diff_lvl = 1
00378         if avg_abs_diff > self._diff_avg_abs_fail:
00379             avg_abs_diff_lvl = 2
00380         
00381         stat_lvl = max(max_diff_lvl, avg_diff_lvl, avg_abs_diff_lvl)
00382         
00383         html = '<p align=center><b>Fingertip Differences</b></p>\n'
00384         html += '<p>Differences given in percent of maximum observed value. Status: %s</p>\n' % lvl_dict[stat_lvl]
00385         html += '<table border="1" cellpadding="2" cellspacing="0">\n'
00386         html += '<tr><td><b>Parameter</b></td><td><b>Value</b></td><td><b>Status</b></td><td><b>Questionable Pt.</b></td><td><b>Failure Pt.</b></td></tr>\n'
00387         html += '<tr><td>Max Diff.</td><td>%.1f</td><td>%s</td><td>%.1f</td><td>%.1f</td></tr>\n' % (max_diff, lvl_dict[max_diff_lvl], self._diff_max_quest, self._diff_max_fail)
00388         html += '<tr><td>Avg. Diff.</td><td>%.1f</td><td>%s</td><td>%.1f</td><td>%.1f</td></tr>\n' % (avg_diff, lvl_dict[avg_diff_lvl], self._diff_avg_quest, self._diff_avg_fail)
00389         html += '<tr><td>Avg. Abs. Diff.</td><td>%.1f</td><td>%s</td><td>%.1f</td><td>%.1f</td></tr>\n' % (avg_abs_diff, lvl_dict[avg_abs_diff_lvl], self._diff_avg_abs_quest, self._diff_avg_abs_fail)
00390 
00391         html += '</table>\n'
00392         
00393         return html, stat_lvl
00394 
00395     ##\brief At every point, check abs dev from expected
00396     def _check_tol(self):
00397         true_vals = numpy.array(self._expected)
00398         tip0_vals = numpy.array(self._tip0)
00399         tip1_vals = numpy.array(self._tip1)
00400         
00401         max_val = 0.5 * max(tip0_vals + tip1_vals)
00402 
00403         # Maximum error 
00404         max_err0 = max(abs(tip0_vals - true_vals)) / max_val * 100
00405         max_err1 = max(abs(tip1_vals - true_vals)) / max_val * 100
00406         
00407         err0_lvl = 0
00408         err1_lvl = 0
00409 
00410         max_val_warn = self._tol_max_quest
00411         max_val_err  = self._tol_max_fail
00412 
00413         if max_err0 > self._tol_max_quest:
00414             err0_lvl = 1
00415         if max_err0 > self._tol_max_fail:
00416             err0_lvl = 2
00417 
00418         if max_err1 > self._tol_max_quest:
00419             err1_lvl = 1
00420         if max_err1 > self._tol_max_fail:
00421             err1_lvl = 2
00422 
00423         # Average error
00424         avg_err0 = abs(numpy.average(tip0_vals - true_vals) / max_val * 100)
00425         avg_err1 = abs(numpy.average(tip1_vals - true_vals) / max_val * 100)
00426 
00427         avg_err0_lvl = 0
00428         avg_err1_lvl = 0
00429         
00430         if avg_err0 > self._tol_avg_quest:
00431             avg_err0_lvl = 1
00432         if avg_err0 > self._tol_avg_fail:
00433             avg_err0_lvl = 2
00434 
00435         if avg_err1 > self._tol_avg_quest:
00436             avg_err1_lvl = 1
00437         if avg_err1 > self._tol_avg_fail:
00438             avg_err1_lvl = 2
00439         
00440         stat_lvl = max(err0_lvl, err1_lvl, avg_err0_lvl, avg_err1_lvl)
00441 
00442         html = '<p align=center><b>Fingertip Error</b></p>\n'
00443         html += '<p>Error from expected value given in percent of maximum observed value. Status: %s</p>\n' % lvl_dict[stat_lvl]
00444         html += '<table border="1" cellpadding="2" cellspacing="0">\n'
00445         html += '<tr><td><b>Parameter</b></td><td><b>Value</b></td><td><b>Status</b></td><td><b>Questionable Pt.</b></td><td><b>Failure Pt.</b></td></tr>\n'
00446         html += '<tr><td>L tip Maximum Error</td><td>%.1f</td><td>%s</td><td>%.1f</td><td>%.1f</td></tr>\n' % (max_err0, lvl_dict[err0_lvl], self._tol_max_quest, self._tol_max_fail)
00447         html += '<tr><td>R tip Maximum Error</td><td>%.1f</td><td>%s</td><td>%.1f</td><td>%.1f</td></tr>\n' % (max_err1, lvl_dict[err1_lvl], self._tol_max_quest, self._tol_max_fail)
00448         html += '<tr><td>L tip Average Error</td><td>%.1f</td><td>%s</td><td>%.1f</td><td>%.1f</td></tr>\n' % (avg_err0, lvl_dict[avg_err0_lvl], self._tol_avg_quest, self._tol_avg_fail)
00449         html += '<tr><td>R tip Average Error</td><td>%.1f</td><td>%s</td><td>%.1f</td><td>%.1f</td></tr>\n' % (avg_err1, lvl_dict[avg_err1_lvl], self._tol_avg_quest, self._tol_avg_fail)
00450         html += '</table>\n'
00451 
00452         return html, stat_lvl
00453 
00454     ##\brief Check pass/fail, write HTML result of all data, parameters
00455     def process_results(self):
00456         tol_html, tol_stat = self._check_tol()
00457         diff_html, diff_stat = self._check_diff()
00458 
00459         html = '<img src="IMG_PATH/finger_tip.png", width=640, height=480 />\n'
00460         html += '<hr size="2">\n' + tol_html
00461         html += '<hr size="2">\n' + diff_html
00462         html += '<hr size="2">\n' + self._write_equation()
00463         html += '<hr size="2">\n' + self._write_params()
00464         html += '<hr size="2">\n' + self._write_tols()
00465         html += '<hr size="2">\n' + self._write_data()
00466         html += '<hr size="2">\n' + self._connected_data
00467                 
00468         result_val = TestResultRequest.RESULT_PASS
00469         if max(tol_stat, diff_stat) == 1:
00470             result_val = TestResultRequest.RESULT_HUMAN_REQUIRED
00471         elif max(tol_stat, diff_stat) > 1:
00472             result_val = TestResultRequest.RESULT_FAIL
00473 
00474         r = TestResultRequest()
00475         r.text_summary = 'Fingertip test. Error tolerance: %s. Tip differences: %s' % (lvl_dict[tol_stat], lvl_dict[diff_stat])
00476         r.html_result = html
00477         r.plots = []
00478         r.result = result_val
00479 
00480         fig = plot.figure(1)
00481         plot.xlabel('Effort')
00482         plot.ylabel('Total pressure')
00483         plot.plot(numpy.array(self._forces), numpy.array(self._expected), label='Expected')
00484         plot.plot(numpy.array(self._forces), numpy.array(self._tip0), label='L tip')
00485         plot.plot(numpy.array(self._forces), numpy.array(self._tip1), label='R tip')
00486         fig.text(.3, .95, 'Fingertip Pressure v. Effort')
00487         plot.legend(shadow=True)
00488         
00489         # Store figure in Plot message
00490         stream = StringIO()
00491         plot.savefig(stream, format="png")
00492         image = stream.getvalue()
00493         p = Plot()
00494         r.plots.append(p)
00495         p.title = 'finger_tip'
00496         p.image = image
00497         p.image_format = 'png'
00498 
00499         self.send_results(r)
00500         
00501 
00502 if __name__ == '__main__':
00503     qual = FingertipQualification()
00504     try:
00505         qual.open_gripper()
00506         if not qual.check_connected():
00507             # We've failed and sent it in, now wait to be terminated
00508             rospy.spin()
00509             import sys
00510             sys.exit()
00511 
00512         # Only check connection, we've sent results already
00513         if qual.check_connect_only:
00514             rospy.spin()
00515             import sys
00516             sys.exit()
00517 
00518         for j in range(0, qual.num_increments):
00519             if rospy.is_shutdown():
00520                 break
00521 
00522             qual.record_zero_val()
00523             qual.close_gripper()
00524             qual.record_increase()
00525             qual.open_gripper()
00526             qual.increment_value()
00527 
00528         qual.process_results()
00529         rospy.spin()
00530     except KeyboardInterrupt:
00531         pass
00532     except Exception, e:
00533         import traceback
00534         print 'Caught exception in fingertip_qualification.\n%s' % traceback.format_exc()
00535         rospy.logerr('Fingertip qualification exception.\n%s' % traceback.format_exc())
00536         qual.test_failed_service_call(traceback.format_exc())
00537 
00538     print 'Quitting fingertip qualification'


qualification
Author(s): Kevin Watts (watts@willowgarage.com), Josh Faust (jfaust@willowgarage.com)
autogenerated on Sat Dec 28 2013 17:57:34