00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 import roslib
00021 import rospy
00022 import sys
00023 import getopt
00024
00025 from threading import Lock
00026 from sr_ronex_msgs.msg import BoolArray
00027 from std_msgs.msg import UInt16MultiArray
00028
00029 roslib.load_manifest('sr_ronex_drivers')
00030
00031 PRODUCT_CODE = "0x05300424"
00032 DIGITAL_IO_WAIT = 0.5
00033 ANALOG_IO_WAIT = 0.1
00034 PWM_O_WAIT = 3.0
00035 ANALOG_RATIO_UPPER = 1.4
00036 ANALOG_RATIO_LOWER = 1.0
00037 PERIOD_ALPHA = 0.01
00038 MAX_PWM_PERIOD = 0.008
00039 MIN_PWM_PERIOD = 0.005
00040
00041
00042 class IoTest(object):
00043 """
00044 A class used to test the Shadow Robot ethercat board HW.
00045 For the PRODUCT_CODE = "0x05300424"
00046 4 digital inputs/outputs/PWM outputs
00047 4 analog inputs
00048 2 analog outputs
00049
00050 The digital outputs will be tested by turning on and off LEDs attached to them.
00051 The digital inputs will read back the value we set for the outputs.
00052 The PWM outputs will be set to their lower frequency, and the digital inputs used to check the on-off period
00053 The analog output 0 will be wired to analog inputs 0 and 2, output 1 to inputs 1 and 3
00054
00055 Keep in mind that the test is intended to be run with the LEDs attached to the digital I/Os and the correct wiring
00056 of the analog I and O
00057 """
00058
00059
00060
00061
00062
00063
00064
00065 def __init__(self, device_SN):
00066 rospy.loginfo("Testing device. Product code: " + PRODUCT_CODE + " SN: " + device_SN)
00067 self.success = True
00068 self.PWM_testing = False
00069 self.device_SN = device_SN
00070 self.a_state_lock = Lock()
00071 self.d_state_lock = Lock()
00072 self.analog_command_publisher = rospy.Publisher("/device_" + PRODUCT_CODE + "_" + device_SN +
00073 "_analog_outputs_command", UInt16MultiArray, latch=True)
00074 self.digital_command_publisher = rospy.Publisher("/device_" + PRODUCT_CODE + "_" + device_SN +
00075 "_digital_outputs_command", BoolArray, latch=True)
00076 self.PWM_command_publisher = rospy.Publisher("/device_" + PRODUCT_CODE + "_" + device_SN +
00077 "_PWM_outputs_command", UInt16MultiArray, latch=True)
00078 self.analog_state_subscriber_ = rospy.Subscriber("/device_" + PRODUCT_CODE + "_" + device_SN +
00079 "_analog_inputs_state", UInt16MultiArray,
00080 self.analog_state_callback)
00081 self.digital_state_subscriber_ = rospy.Subscriber("/device_" + PRODUCT_CODE + "_" + device_SN +
00082 "_digital_inputs_state", BoolArray,
00083 self.digital_state_callback)
00084
00085 self.last_analog_state = None
00086 self.last_digital_state = None
00087 self.last_period_start_time = [0.0, 0.0, 0.0, 0.0]
00088 self.average_period = [0.0, 0.0, 0.0, 0.0]
00089
00090
00091 command_msg = UInt16MultiArray(None, [0, 0, 0, 0, 0, 0, 0, 0])
00092 self.PWM_command_publisher.publish(command_msg)
00093 rospy.sleep(0.2)
00094
00095 def analog_state_callback(self, msg):
00096 with self.a_state_lock:
00097 self.last_analog_state = msg
00098
00099 def digital_state_callback(self, msg):
00100 with self.d_state_lock:
00101 if self.PWM_testing:
00102 for i, value in enumerate(self.last_digital_state.data):
00103
00104 if value and not msg.data[i]:
00105 if self.last_period_start_time[i] != 0.0:
00106 self.average_period[i] = (1 - PERIOD_ALPHA) * self.average_period[i] + \
00107 PERIOD_ALPHA * (rospy.get_time() - self.last_period_start_time[i])
00108 self.last_period_start_time[i] = rospy.get_time()
00109 self.last_digital_state = msg
00110
00111 def check_digital_inputs(self, output_values):
00112 rospy.sleep(0.1)
00113 with self.d_state_lock:
00114 if self.last_digital_state is not None:
00115 for i, value in enumerate(output_values):
00116 if i & 1:
00117 if self.last_digital_state.data[i/2] != value:
00118 rospy.logerr("Wrong value in digital input " + str(i/2))
00119 self.success = False
00120 else:
00121 rospy.logerr("No digital input data recived from: " + self.device_SN)
00122 self.success = False
00123
00124 def test_digital_io_case(self, output_values):
00125 command_msg = BoolArray(output_values)
00126 self.digital_command_publisher.publish(command_msg)
00127 self.check_digital_inputs(output_values)
00128 rospy.sleep(DIGITAL_IO_WAIT)
00129
00130 def test_digital_ios(self):
00131 rospy.loginfo("Testing digital I/O")
00132 self.test_digital_io_case([False, False, False, False, False, False, False, False])
00133 self.test_digital_io_case([False, True, False, False, False, False, False, False])
00134 self.test_digital_io_case([False, False, False, True, False, False, False, False])
00135 self.test_digital_io_case([False, False, False, False, False, True, False, False])
00136 self.test_digital_io_case([False, False, False, False, False, False, False, True])
00137 self.test_digital_io_case([False, True, False, True, False, True, False, True])
00138 self.test_digital_io_case([False, False, False, False, False, False, False, False])
00139 rospy.loginfo("Digital I/O test ended")
00140
00141 def check_analog_inputs(self, output_values):
00142 rospy.sleep(0.1)
00143 with self.a_state_lock:
00144 if self.last_analog_state is not None:
00145 for i, value in enumerate(output_values):
00146 index = i
00147 if (float(value) / float(self.last_analog_state.data[index])) > ANALOG_RATIO_UPPER or \
00148 (float(value) / float(self.last_analog_state.data[index])) < ANALOG_RATIO_LOWER:
00149 rospy.logerr("Wrong value in analog input " + str(index) + " set: " + str(value) +
00150 " measured: " + str(self.last_analog_state.data[index]) + " ratio: " +
00151 str(float(value) / float(self.last_analog_state.data[index])))
00152 self.success = False
00153 index = i + 2
00154 if (float(value) / float(self.last_analog_state.data[index])) > ANALOG_RATIO_UPPER or \
00155 (float(value) / float(self.last_analog_state.data[index])) < ANALOG_RATIO_LOWER:
00156 rospy.logerr("Wrong value in analog input " + str(index) + " set: " + str(value) +
00157 " measured: " + str(self.last_analog_state.data[index]) + " ratio: " +
00158 str(float(value) / float(self.last_analog_state.data[index])))
00159 self.success = False
00160 else:
00161 rospy.logerr("No analog input data received from: " + self.device_SN)
00162 self.success = False
00163
00164 def test_analog_io_case(self, output_values):
00165 command_msg = UInt16MultiArray(None, output_values)
00166 self.analog_command_publisher.publish(command_msg)
00167 self.check_analog_inputs(output_values)
00168 rospy.sleep(ANALOG_IO_WAIT)
00169
00170 def test_analog_ios(self):
00171 rospy.loginfo("Testing analog I/O")
00172 rospy.sleep(0.1)
00173 self.test_analog_io_case([0x200, 0x200])
00174 self.test_analog_io_case([0x200, 0xFF00])
00175 self.test_analog_io_case([0xFF00, 0x200])
00176 self.test_analog_io_case([0x200, 0x200])
00177 self.test_analog_io_case([0x300, 0x300])
00178 self.test_analog_io_case([0x1000, 0x1000])
00179 self.test_analog_io_case([0x5000, 0x5000])
00180 self.test_analog_io_case([0x8000, 0x8000])
00181 self.test_analog_io_case([0xA000, 0xA000])
00182 self.test_analog_io_case([0xC000, 0xC000])
00183 self.test_analog_io_case([0xD000, 0xD000])
00184 self.test_analog_io_case([0xE000, 0xE000])
00185 self.test_analog_io_case([0xF000, 0xF000])
00186 self.test_analog_io_case([0xFF00, 0xFF00])
00187 rospy.loginfo("Analog I/O test ended")
00188
00189 def test_PWM_o_case(self, output_values):
00190 command_msg = UInt16MultiArray(None, output_values)
00191 self.PWM_testing = True
00192 self.PWM_command_publisher.publish(command_msg)
00193
00194 rospy.sleep(PWM_O_WAIT)
00195 for i, value in enumerate(self.average_period):
00196 if value > MAX_PWM_PERIOD or value < MIN_PWM_PERIOD:
00197 rospy.logerr("Wrong period in PWM output " + str(i) + " measured period: " + str(value))
00198 self.success = False
00199 self.PWM_testing = False
00200
00201 def test_PWM_outputs(self):
00202 rospy.loginfo("Testing PWM outputs")
00203 self.test_PWM_o_case([0xFFFE, 0x8000, 0xFFFE, 0x8000, 0xFFFE, 0x8000, 0xFFFE, 0x8000])
00204 rospy.loginfo("PWM outputs test ended")
00205
00206 def ramp(self):
00207 for i in range(0, 65535, 0x100):
00208 command_msg = UInt16MultiArray(None, [i, i])
00209 self.analog_command_publisher.publish(command_msg)
00210 rospy.sleep(0.03)
00211
00212 def run_test(self):
00213 self.test_digital_ios()
00214 self.test_analog_ios()
00215 self.test_PWM_outputs()
00216
00217 if self.success:
00218 rospy.loginfo("NO ERRORS DETECTED. Product code: " + PRODUCT_CODE + " SN: " + self.device_SN)
00219 else:
00220 rospy.logerr("TEST FAILED. ERRORS DETECTED!!!!!!!!!!!!!!!!!!!!!!!!!! Product code: " + PRODUCT_CODE +
00221 " SN: " + self.device_SN)
00222
00223
00224 def main(argv):
00225 try:
00226 opts, args = getopt.getopt(argv, "h")
00227 except getopt.GetoptError:
00228 print 'io_test.py <SN_device_1> ... <SN_device_N>'
00229 sys.exit(2)
00230 for opt, arg in opts:
00231 if opt == '-h':
00232 print 'io_test.py <SN_device_1> ... <SN_device_N>'
00233 sys.exit()
00234
00235 if len(args) == 0:
00236 print 'io_test.py <SN_device_1> ... <SN_device_N>'
00237 sys.exit(2)
00238
00239
00240 rospy.init_node('IO_test', anonymous=True)
00241 rospy.sleep(0.5)
00242
00243 for arg in args:
00244 io_test = IoTest(arg)
00245 io_test.run_test()
00246
00247 rospy.loginfo("I/O test ended")
00248
00249
00250
00251
00252 if __name__ == '__main__':
00253 main(sys.argv[1:])