Go to the documentation of this file.00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032 PKG = "qualification"
00033 import roslib; roslib.load_manifest(PKG)
00034
00035 import numpy
00036
00037 import rospy
00038
00039 from pr2_self_test_msgs.srv import TestResult, TestResultRequest
00040 from qualification.analysis.hysteresis_analysis import *
00041
00042 from joint_qualification_controllers.msg import HysteresisData2
00043 from std_msgs.msg import Bool
00044
00045 import traceback
00046
00047 class AnalysisApp:
00048 def __init__(self):
00049 self.data_sent = False
00050 self._motors_halted = True
00051 rospy.init_node("test_plotter")
00052 self.data_topic = rospy.Subscriber("/test_data", HysteresisData2, self._on_data)
00053 self.motors_topic = rospy.Subscriber("pr2_etherCAT/motors_halted", Bool, self.on_motor_cb)
00054 self.result_service = rospy.ServiceProxy('/test_result', TestResult)
00055 self.data = None
00056
00057 def _on_data(self, msg):
00058 self.data = msg
00059
00060 def has_data(self):
00061 return self.data is not None
00062
00063 def on_motor_cb(self, msg):
00064 self._motors_halted = msg.data
00065
00066 def test_failed_service_call(self, except_str = ''):
00067 rospy.logerr(except_str)
00068 r = TestResultRequest()
00069 r.html_result = except_str
00070 r.text_summary = 'Caught exception, automated test failure.'
00071 r.plots = []
00072 r.result = TestResultRequest.RESULT_FAIL
00073 self.send_results(r)
00074
00075 def send_results(self, test_result):
00076 if not self.data_sent:
00077 rospy.wait_for_service('test_result')
00078 self.result_service.call(test_result)
00079 self.data_sent = True
00080
00081 def hysteresis_plot(self):
00082 try:
00083 r = TestResultRequest()
00084 r.html_result = ''
00085 r.text_summary = 'No data.'
00086 r.plots = []
00087 r.result = TestResultRequest.RESULT_FAIL
00088
00089 image_title = self.data.joint_name + "_hysteresis"
00090
00091 params = HysteresisParameters()
00092 params.joint_name = self.data.joint_name
00093 params.pos_effort = self.data.arg_value[1]
00094 params.neg_effort = self.data.arg_value[0]
00095 params.range_max = self.data.arg_value[3]
00096 params.range_min = self.data.arg_value[2]
00097 params.tolerance = self.data.arg_value[7]
00098 params.sd_max = self.data.arg_value[8]
00099 params.slope = self.data.arg_value[9]
00100 params.timeout = self.data.arg_value[5]
00101 params.velocity = self.data.arg_value[4]
00102 params.max_effort = self.data.arg_value[6]
00103
00104 params.p_gain = self.data.arg_value[10]
00105 params.i_gain = self.data.arg_value[11]
00106 params.d_gain = self.data.arg_value[12]
00107 params.i_clamp = self.data.arg_value[13]
00108
00109 r.params = params.get_test_params()
00110
00111 if self._motors_halted:
00112 r.result = TestResultRequest.RESULT_FAIL
00113 r.text_summary = "Motors halted. Check runstop. Hysteresis results are invalid."
00114 r.html_result = "<p>Motors halted during test. Check estop and verify that power is on.</p>\n"
00115 self.send_results(r)
00116
00117
00118 min_len = min( len(d.position) for d in self.data.runs )
00119 if min_len < 20:
00120 r.result = TestResultRequest.RESULT_FAIL
00121 r.text_summary = "Not enough data points, bad encoder or bad gains."
00122
00123 error_msg = "<p>Not enough data points, hysteresis controller may have malfunctioned. Check diagnostics.</p>"
00124 error_msg += "<p>Up data points: %d, down points: %d</p>\n" % (len(self.data.position_up), len(self.data.position_down))
00125 error_msg += "<p>The encoder may be missing ticks, check encoder.<br>\n"
00126 error_msg += "Make sure mechanism is free to move and not trapped or constrained<br>\n"
00127 error_msg += "Make sure motors are not in safety lockout (check diagnostics)<br>\n"
00128 error_msg += "Check controller gains if problem persists on components of same type.</p>\n"
00129 error_msg += "<p>Test status: <b>FAIL</b>.</p>"
00130 error_msg += '<p align=center><b>Test Parameters</b></p>\n'
00131
00132 r.html_result = error_msg
00133 self.send_results(r)
00134 return
00135
00136 if self.data.arg_value[5] == 0:
00137 r.result = TestResultRequest.RESULT_FAIL
00138 r.text_summary = 'Hysteresis controller timed out. Check diagnostics.'
00139 r.html_result = '<p>Hysteresis controller timed out. Check diagnostics. Controller gains may be bad, or motors may be in safety lockout. Did the device pass the visualizer? Is it calibrated?</p><p>Test status: <b>FAIL</b>.</p>'
00140 r.html_result += '<p align=center><b>Test Parameters</b></p>\n'
00141 self.send_results(r)
00142 return
00143
00144
00145 min_encoder = min( min(numpy.array(d.position)) for d in self.data.runs )
00146 max_encoder = max( max(numpy.array(d.position)) for d in self.data.runs )
00147
00148 if abs(max_encoder - min_encoder) < 0.005:
00149 r.result = TestResultRequest.RESULT_FAIL
00150 r.text_summary = 'Mechanism didn\'t move. Check diagnostics.'
00151 r.html_result = "<p>No travel of mechanism, hysteresis did not complete. Check controller gains and encoder.</p><p>Test status: <b>FAIL</b>.</p>"
00152 r.html_result += '<p align=center><b>Test Parameters</b></p>\n'
00153 self.send_results(r)
00154 return
00155
00156 hyst_data = HysteresisTestData2([ HysteresisDirectionData(d.position, d.effort, d.velocity) for d in self.data.runs ])
00157
00158
00159 if min_len < 20:
00160 r.result = TestResultRequest.RESULT_FAIL
00161 r.text_summary = 'Incomplete data set. Check diagnostics.'
00162 r.html_result = "<p>Not enough data in one or more directions.</p><p>Test Status: <b>FAIL</b>.</p><p>Test status: <b>FAIL</b>.</p>"
00163 r.html_result += '<p align=center><b>Test Parameters</b></p>\n'
00164 self.send_results(r)
00165 return
00166
00167
00168 range_result = range_analysis(params, hyst_data)
00169
00170 if params.slope == 0:
00171 effort_result = effort_analysis(params, hyst_data)
00172
00173
00174
00175
00176 vel_result = velocity_analysis(params, hyst_data)
00177 vel_html = vel_result.html
00178
00179
00180 effort_plots = plot_efforts(params, hyst_data)
00181 vel_plots = plot_velocities(params, hyst_data)
00182
00183
00184 csv = Plot()
00185 csv.image_format = "csv"
00186 csv.title = params.joint_name + "_hysteresis_csv"
00187 csv_data = "Run,Position,Effort,Velocity\n"
00188 for i, run in enumerate(self.data.runs):
00189 for j in range(len(run.position)):
00190 csv_data = csv_data + "%d,%f,%f,%f\n"%(i, run.position[j], run.effort[j], run.velocity[j])
00191 csv.image = csv_data
00192
00193 r.plots = effort_plots + vel_plots + [csv]
00194
00195 html = ""
00196 for p in effort_plots:
00197 html += '<img src=\"IMG_PATH/%s.png\", width = 640, height = 480/>' % p.title
00198 html += '<p><b>Legend:</b> Red - Average Effort. Yellow - Error Bars. Green - Expected Effort.</p>\n'
00199 html += '<p align=center><b>Range Data</b></p>' + range_result.html + '<hr size="2">\n'
00200 html += '<p align=center><b>Effort Data</b></p>' + effort_result.html + '<hr size="2">\n'
00201
00202 html += '<p align=center><b>Velocity Data</b></p>'
00203
00204 for p in vel_plots:
00205 html += '<img src=\"IMG_PATH/%s.png\", width = 640, height = 480/>' % p.title
00206
00207 html += vel_html + '<hr size="2">\n'
00208 html += '<p align=center><b>Test Parameters</b></p>\n'
00209
00210
00211 r.html_result = html
00212
00213 r.values.extend(effort_result.values)
00214 r.values.extend(range_result.values)
00215 r.values.extend(vel_result.values)
00216
00217 if range_result.result and effort_result.result:
00218 r.text_summary = 'Hysteresis result: OK'
00219 r.result = TestResultRequest.RESULT_PASS
00220 elif not range_result.result:
00221 r.text_summary = 'Hysteresis range failed. Joint did not complete range of motion.'
00222 r.result = TestResultRequest.RESULT_FAIL
00223 else:
00224 r.text_summary = 'Hysteresis result: Questionable. ' + range_result.summary + ' ' + effort_result.summary
00225 r.result = TestResultRequest.RESULT_HUMAN_REQUIRED
00226
00227 self.send_results(r)
00228 except Exception, e:
00229 rospy.logerr('hysteresis_plot caught exception, returning test failure.')
00230 rospy.logerr(traceback.format_exc())
00231 self.test_failed_service_call(traceback.format_exc())
00232
00233
00234 if __name__ == "__main__":
00235 try:
00236 app = AnalysisApp()
00237 my_rate = rospy.Rate(5)
00238 while not rospy.is_shutdown() and not app.has_data():
00239 my_rate.sleep()
00240
00241 if not rospy.is_shutdown():
00242 app.hysteresis_plot()
00243 rospy.spin()
00244 except KeyboardInterrupt:
00245 pass
00246 except Exception, e:
00247 traceback.print_exc()
00248