test_hw.py
Go to the documentation of this file.
1 from enum import Enum
2 
3 import time
4 
5 import rospy
6 import rosnode
7 import rospkg
8 
9 from leo_msgs.msg import Imu, WheelStates
10 from geometry_msgs.msg import Twist
11 from std_msgs.msg import Float32
12 from .utils import write_flush
13 from .board import BoardType, determine_board, check_firmware_version
14 from .utils import CSIColor, parse_yaml
15 
16 
17 class TestMode(Enum):
18  ENCODER = "encoder"
19  TORQUE = "torque"
20  IMU = "imu"
21  BATTERY = "battery"
22  ALL = "all"
23 
24  def __str__(self):
25  return self.value
26 
27 
29  is_new_imu_data = 0
30  is_new_wheel_data = 0
31  is_new_battery_data = 0
32  is_wheel_loaded = 1
33 
34  imu_data = Imu()
35  wheel_data = WheelStates()
36  battery_data = Float32()
37 
38  def __init__(self) -> None:
39  self.rospack = rospkg.RosPack()
40  self.path = self.rospack.get_path("leo_fw") + "/test_data/"
41 
42 
43 
44  self.cmd_vel_pub = rospy.Publisher("cmd_vel", Twist, queue_size=1)
45  self.cmd_pwmfl_pub = rospy.Publisher(
46  "firmware/wheel_FL/cmd_pwm_duty", Float32, queue_size=1
47  )
48  self.cmd_pwmrl_pub = rospy.Publisher(
49  "firmware/wheel_RL/cmd_pwm_duty", Float32, queue_size=1
50  )
51  self.cmd_pwmfr_pub = rospy.Publisher(
52  "firmware/wheel_FR/cmd_pwm_duty", Float32, queue_size=1
53  )
54  self.cmd_pwmrr_pub = rospy.Publisher(
55  "firmware/wheel_RR/cmd_pwm_duty", Float32, queue_size=1
56  )
57  self.cmd_velfl_pub = rospy.Publisher(
58  "firmware/wheel_FL/cmd_velocity", Float32, queue_size=1
59  )
60  self.cmd_velrl_pub = rospy.Publisher(
61  "firmware/wheel_RL/cmd_velocity", Float32, queue_size=1
62  )
63  self.cmd_velfr_pub = rospy.Publisher(
64  "firmware/wheel_FR/cmd_velocity", Float32, queue_size=1
65  )
66  self.cmd_velrr_pub = rospy.Publisher(
67  "firmware/wheel_RR/cmd_velocity", Float32, queue_size=1
68  )
69 
70 
71 
72  self.battery_sub = rospy.Subscriber(
73  "firmware/battery", Float32, self.battery_callback
74  )
75  self.wheel_sub = rospy.Subscriber(
76  "firmware/wheel_states", WheelStates, self.wheel_callback
77  )
78  self.imu_sub = rospy.Subscriber("firmware/imu", Imu, self.imu_callback)
79 
80  def battery_callback(self, data: Float32) -> None:
81  self.battery_data = data
83 
84  def imu_callback(self, data: Imu) -> None:
85  self.imu_data = data
86  self.is_new_imu_data = 1
87 
88  def wheel_callback(self, data: WheelStates) -> None:
89  self.wheel_data = data
91 
92  def check_motor_load(self) -> None:
93  speed_limit = 1
94 
95  for pwm in range(30):
96  self.cmd_pwmfl_pub.publish(Float32(pwm))
97  self.cmd_pwmfr_pub.publish(Float32(pwm))
98  self.cmd_pwmrl_pub.publish(Float32(-pwm))
99  self.cmd_pwmrr_pub.publish(Float32(-pwm))
100 
101  if (
102  self.wheel_data.velocity[0] > speed_limit
103  and self.wheel_data.velocity[1] < -speed_limit
104  and self.wheel_data.velocity[2] > speed_limit
105  and self.wheel_data.velocity[3] < -speed_limit
106  ):
108  break
109 
110  rospy.sleep(0.2)
111 
112  if self.is_wheel_loaded:
113  print(CSIColor.OKGREEN + "LOAD" + CSIColor.ENDC)
114  else:
115  print(CSIColor.OKGREEN + "UNLOAD" + CSIColor.ENDC)
116 
117  self.cmd_pwmfl_pub.publish(Float32(0))
118  self.cmd_pwmfr_pub.publish(Float32(0))
119  self.cmd_pwmrl_pub.publish(Float32(0))
120  self.cmd_pwmrr_pub.publish(Float32(0))
121 
122  def check_encoder(self) -> None:
123  is_error = 0
124  is_error_tab = [0, 0, 0, 0]
125 
126  if self.is_wheel_loaded == 1:
127  wheel_valid = parse_yaml(self.path + "encoder_load.yaml")
128  elif self.is_wheel_loaded == 0:
129  wheel_valid = parse_yaml(self.path + "encoder.yaml")
130 
131  for wheel_test in wheel_valid["tests"]:
132  self.cmd_velfl_pub.publish(wheel_test["velocity"])
133  self.cmd_velfr_pub.publish(wheel_test["velocity"])
134  self.cmd_velrl_pub.publish(wheel_test["velocity"])
135  self.cmd_velrr_pub.publish(wheel_test["velocity"])
136 
137  rospy.sleep(wheel_test["time"])
138 
139  speed_min = wheel_test["velocity"] - wheel_test["offset"]
140  speed_max = wheel_test["velocity"] + wheel_test["offset"]
141 
142  for i in range(0, 4):
143  if not speed_min < self.wheel_data.velocity[i] < speed_max:
144  is_error = 1
145  is_error_tab[i] = 1
146 
147  self.cmd_velfl_pub.publish(Float32(0))
148  self.cmd_velfr_pub.publish(Float32(0))
149  self.cmd_velrl_pub.publish(Float32(0))
150  self.cmd_velrr_pub.publish(Float32(0))
151 
152  if is_error == 1:
153  error_msg = "ERROR WHEEL ENCODER "
154  error_msg += str(is_error_tab)
155  print(CSIColor.FAIL + error_msg + CSIColor.ENDC)
156  return
157 
158  print(CSIColor.OKGREEN + "PASSED" + CSIColor.ENDC)
159  return
160 
161  def check_torque(self) -> None:
162  is_error = 0
163  is_error_tab = [0, 0, 0, 0]
164 
165  if self.is_wheel_loaded == 1:
166  torque_valid = parse_yaml(self.path + "torque_load.yaml")
167  elif self.is_wheel_loaded == 0:
168  torque_valid = parse_yaml(self.path + "torque.yaml")
169 
170  for torque_test in torque_valid["tests"]:
171  self.cmd_pwmfl_pub.publish(torque_test["pwm"])
172  self.cmd_pwmfr_pub.publish(torque_test["pwm"])
173  self.cmd_pwmrl_pub.publish(-torque_test["pwm"])
174  self.cmd_pwmrr_pub.publish(-torque_test["pwm"])
175 
176  rospy.sleep(torque_test["time"])
177 
178  torque_min = torque_test["torque"]
179  torque_max = torque_test["torque"] + 1
180 
181  for i in range(0, 4):
182  if not torque_min < self.wheel_data.torque[i] < torque_max:
183  is_error = 1
184  is_error_tab[i] = 1
185 
186  self.cmd_pwmfl_pub.publish(Float32(0))
187  self.cmd_pwmfr_pub.publish(Float32(0))
188  self.cmd_pwmrl_pub.publish(Float32(0))
189  self.cmd_pwmrr_pub.publish(Float32(0))
190 
191  if is_error == 1:
192  error_msg = "ERROR WHEEL TORQUE "
193  error_msg += str(is_error_tab)
194  print(CSIColor.FAIL + error_msg + CSIColor.ENDC)
195  return
196 
197  print(CSIColor.OKGREEN + "PASSED" + CSIColor.ENDC)
198  return
199 
200  def check_imu(self) -> None:
201  msg_cnt = 0
202  time_now = time.time()
203  imu_valid = parse_yaml(self.path + "imu.yaml")
204 
205  accel_del = imu_valid["imu"]["accel_del"]
206  accel_x = imu_valid["imu"]["accel_x"]
207  accel_y = imu_valid["imu"]["accel_y"]
208  accel_z = imu_valid["imu"]["accel_z"]
209 
210  gyro_del = imu_valid["imu"]["gyro_del"]
211  gyro_x = imu_valid["imu"]["gyro_x"]
212  gyro_y = imu_valid["imu"]["gyro_y"]
213  gyro_z = imu_valid["imu"]["gyro_z"]
214 
215  while msg_cnt < 50:
216  if time_now + imu_valid["imu"]["timeout"] < time.time():
217  print(CSIColor.WARNING + "TIMEOUT" + CSIColor.ENDC)
218  return
219 
220  if self.is_new_imu_data == 1:
221  time_now = time.time()
222  self.is_new_imu_data = 0
223  msg_cnt += 1
224 
225  if not (
226  accel_x - accel_del < self.imu_data.accel_x < accel_x + accel_del
227  and accel_y - accel_del
228  < self.imu_data.accel_y
229  < accel_y + accel_del
230  and accel_z - accel_del
231  < abs(self.imu_data.accel_z)
232  < accel_z + accel_del
233  and gyro_x - gyro_del < self.imu_data.gyro_x < gyro_x + gyro_del
234  and gyro_y - gyro_del < self.imu_data.gyro_y < gyro_y + gyro_del
235  and gyro_z - gyro_del < self.imu_data.gyro_z < gyro_z + gyro_del
236  ):
237  print(CSIColor.FAIL + "INVALID DATA" + CSIColor.ENDC)
238  return
239 
240  print(CSIColor.OKGREEN + "PASSED" + CSIColor.ENDC)
241  return
242 
243  def check_battery(self) -> None:
244  msg_cnt = 0
245  time_now = time.time()
246  batt_valid = parse_yaml(self.path + "battery.yaml")
247 
248  while msg_cnt < 50:
249  if time_now + batt_valid["battery"]["timeout"] < time.time():
250  print(CSIColor.WARNING + "TIMEOUT" + CSIColor.ENDC)
251  return
252 
253  if self.is_new_battery_data == 1:
254  time_now = time.time()
255  self.is_new_battery_data = 0
256  msg_cnt += 1
257 
258  if self.battery_data.data <= batt_valid["battery"]["voltage_min"]:
259  print(CSIColor.FAIL + "LOW VOLTAGE" + CSIColor.ENDC)
260  return
261  if self.battery_data.data >= batt_valid["battery"]["voltage_max"]:
262  print(CSIColor.FAIL + "HIGH VOLTAGE" + CSIColor.ENDC)
263  return
264 
265  print(CSIColor.OKGREEN + "PASSED" + CSIColor.ENDC)
266  return
267 
268  # pylint: disable=too-many-branches,too-many-statements
269  def test_hw(
270  self,
271  hardware: TestMode = TestMode.ALL,
272  ) -> None:
273  write_flush("--> Checking if rosserial node is active.. ")
274 
275  if rospy.resolve_name("serial_node") in rosnode.get_node_names():
276  print("YES")
277  serial_node_active = True
278  else:
279  print("NO")
280  serial_node_active = False
281  print(
282  "Rosserial node is not active. "
283  "Will not be able to validate hardware."
284  "Try to restart leo.service or reboot system."
285  )
286  return
287 
288  if serial_node_active:
289  write_flush("--> Trying to determine board type.. ")
290 
291  board_type = determine_board()
292 
293  if board_type is not None:
294  print("SUCCESS")
295  else:
296  print("FAIL")
297 
298  current_firmware_version = "<unknown>"
299 
300  if serial_node_active:
301  write_flush("--> Trying to check the current firmware version.. ")
302 
303  current_firmware_version = check_firmware_version()
304 
305  if current_firmware_version != "<unknown>":
306  print("SUCCESS")
307  else:
308  print("FAIL")
309 
310  if current_firmware_version == "<unknown>" or board_type is None:
311  print(
312  "Can not determine firmware version or board type. "
313  "Flash firmware and try to rerun the script"
314  )
315  return
316 
317  if serial_node_active:
318  write_flush("--> Initializing ROS node.. ")
319  rospy.init_node("leo_core_validation", anonymous=True)
320  print("OK")
321 
322  print(f"Firmware version: {current_firmware_version}")
323  if board_type == BoardType.CORE2:
324  print(f"Board type: Core2ROS")
325  elif board_type == BoardType.LEOCORE:
326  print(f"Board type: LeoCore")
327  else:
328  print(f"Can not determine board version")
329  return
330 
331  if hardware in (TestMode.ALL, TestMode.BATTERY):
332  write_flush("--> Battery validation.. ")
333  self.check_battery()
334 
335  if hardware in (TestMode.ALL, TestMode.IMU) and board_type == BoardType.LEOCORE:
336  write_flush("--> IMU validation.. ")
337  self.check_imu()
338 
339  if hardware in (TestMode.ALL, TestMode.TORQUE, TestMode.ENCODER):
340  write_flush("--> Motors load test.. ")
341  self.check_motor_load()
342 
343  if hardware in (TestMode.ALL, TestMode.ENCODER):
344  write_flush("--> Encoders validation.. ")
345  self.check_encoder()
346 
347  if (
348  hardware in (TestMode.ALL, TestMode.TORQUE)
349  and board_type == BoardType.LEOCORE
350  ):
351  write_flush("--> Torque sensors validation.. ")
352  self.check_torque()
leo_fw.test_hw.HardwareTester.cmd_velfl_pub
cmd_velfl_pub
Definition: test_hw.py:57
leo_fw.test_hw.HardwareTester.imu_sub
imu_sub
Definition: test_hw.py:78
leo_fw.test_hw.HardwareTester.battery_data
battery_data
Definition: test_hw.py:36
leo_fw.test_hw.HardwareTester.cmd_pwmfl_pub
cmd_pwmfl_pub
Definition: test_hw.py:45
leo_fw.test_hw.HardwareTester.cmd_velrl_pub
cmd_velrl_pub
Definition: test_hw.py:60
leo_fw.test_hw.HardwareTester.__init__
None __init__(self)
Definition: test_hw.py:38
leo_fw.test_hw.HardwareTester.is_wheel_loaded
int is_wheel_loaded
Definition: test_hw.py:32
leo_fw.test_hw.HardwareTester.path
path
Definition: test_hw.py:40
leo_fw.test_hw.HardwareTester.cmd_vel_pub
cmd_vel_pub
Publisher.
Definition: test_hw.py:44
leo_fw.board.determine_board
Optional[BoardType] determine_board()
Definition: board.py:18
leo_fw.test_hw.HardwareTester.wheel_callback
None wheel_callback(self, WheelStates data)
Definition: test_hw.py:88
leo_fw.test_hw.HardwareTester
Definition: test_hw.py:28
leo_fw.test_hw.HardwareTester.is_new_wheel_data
int is_new_wheel_data
Definition: test_hw.py:30
leo_fw.test_hw.HardwareTester.check_encoder
None check_encoder(self)
Definition: test_hw.py:122
leo_fw.test_hw.HardwareTester.check_battery
None check_battery(self)
Definition: test_hw.py:243
leo_fw.test_hw.HardwareTester.wheel_sub
wheel_sub
Definition: test_hw.py:75
leo_fw.test_hw.HardwareTester.cmd_pwmrl_pub
cmd_pwmrl_pub
Definition: test_hw.py:48
leo_fw.test_hw.HardwareTester.imu_data
imu_data
Definition: test_hw.py:34
leo_fw.test_hw.HardwareTester.battery_callback
None battery_callback(self, Float32 data)
Definition: test_hw.py:80
leo_fw.test_hw.HardwareTester.imu_callback
None imu_callback(self, Imu data)
Definition: test_hw.py:84
leo_fw.test_hw.HardwareTester.cmd_velrr_pub
cmd_velrr_pub
Definition: test_hw.py:66
leo_fw.test_hw.HardwareTester.check_imu
None check_imu(self)
Definition: test_hw.py:200
leo_fw.test_hw.HardwareTester.battery_sub
battery_sub
Subscriber.
Definition: test_hw.py:72
leo_fw.board.check_firmware_version
str check_firmware_version()
Definition: board.py:36
leo_fw.test_hw.HardwareTester.rospack
rospack
Definition: test_hw.py:39
leo_fw.test_hw.HardwareTester.cmd_velfr_pub
cmd_velfr_pub
Definition: test_hw.py:63
leo_fw.test_hw.HardwareTester.check_motor_load
None check_motor_load(self)
Definition: test_hw.py:92
leo_fw.test_hw.HardwareTester.test_hw
None test_hw(self, TestMode hardware=TestMode.ALL)
Definition: test_hw.py:269
leo_fw.test_hw.HardwareTester.cmd_pwmfr_pub
cmd_pwmfr_pub
Definition: test_hw.py:51
leo_fw.test_hw.HardwareTester.check_torque
None check_torque(self)
Definition: test_hw.py:161
leo_fw.test_hw.TestMode
Definition: test_hw.py:17
leo_fw.test_hw.HardwareTester.wheel_data
wheel_data
Definition: test_hw.py:35
leo_fw.utils.write_flush
def write_flush(str msg)
Write a message to standard output and flush the buffer.
Definition: utils.py:28
leo_fw.test_hw.HardwareTester.cmd_pwmrr_pub
cmd_pwmrr_pub
Definition: test_hw.py:54
leo_fw.test_hw.TestMode.__str__
def __str__(self)
Definition: test_hw.py:24
leo_fw.test_hw.HardwareTester.is_new_imu_data
int is_new_imu_data
Definition: test_hw.py:29
leo_fw.utils.parse_yaml
def parse_yaml(str file_path)
Definition: utils.py:79
leo_fw.test_hw.HardwareTester.is_new_battery_data
int is_new_battery_data
Definition: test_hw.py:31


leo_fw
Author(s): Błażej Sowa , Aleksander Szymański
autogenerated on Sat Jul 6 2024 03:05:11