emergency_stop_monitor.py
Go to the documentation of this file.
1 #!/usr/bin/env python
2 #
3 # Copyright 2017 Fraunhofer Institute for Manufacturing Engineering and Automation (IPA)
4 #
5 # Licensed under the Apache License, Version 2.0 (the "License");
6 # you may not use this file except in compliance with the License.
7 # You may obtain a copy of the License at
8 #
9 # http://www.apache.org/licenses/LICENSE-2.0
10 #
11 # Unless required by applicable law or agreed to in writing, software
12 # distributed under the License is distributed on an "AS IS" BASIS,
13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 # See the License for the specific language governing permissions and
15 # limitations under the License.
16 
17 
18 import sys
19 import copy
20 from enum import IntEnum
21 
22 import rospy
23 from std_msgs.msg import Empty
24 from sensor_msgs.msg import JointState
25 from diagnostic_msgs.msg import DiagnosticStatus, DiagnosticArray
26 
27 from cob_msgs.msg import *
28 from cob_light.msg import LightMode, LightModes, SetLightModeGoal, SetLightModeAction
29 from cob_light.srv import StopLightMode, StopLightModeRequest
30 
31 from simple_script_server import *
33 
34 class EMState(IntEnum):
35  EM_UNKNOWN = -1
36  EM_FREE = 0
37  EM_BUTTON = 1
38  EM_BRAKE = 2
39  EM_LASER = 3
40  EM_WIRELESS = 4
41  EM_FALL = 5
42  EM_INTERNAL = 6
43 
44 
46  def __init__(self):
47  self.color = "None"
48  self.enable_sound = rospy.get_param("~enable_sound", False)
49  self.enable_light = rospy.get_param("~enable_light", False)
50  self.diagnostics_based = rospy.get_param("~diagnostics_based", False)
51  self.motion_based = rospy.get_param("~motion_based", False)
52  self.track_id_light = None
53 
54  if(self.enable_light):
55  if not rospy.has_param("~light_components"):
56  rospy.logwarn("parameter light_components does not exist on ROS Parameter Server, aborting...")
57  sys.exit(1)
58  self.light_components = rospy.get_param("~light_components")
59 
60  # set colors (also neccessary if self.enable_light is false)
61  self.color_error = rospy.get_param("~color_error","red")
62  self.color_warn = rospy.get_param("~color_warn","yellow")
63  self.color_ok = rospy.get_param("~color_ok","green")
64  self.color_off = rospy.get_param("~color_off","black")
65 
66  if(self.enable_sound):
67  if not rospy.has_param("~sound_components"):
68  rospy.logwarn("parameter sound_components does not exist on ROS Parameter Server, aborting...")
69  sys.exit(1)
70  self.sound_components = rospy.get_param("~sound_components")
71 
72  self.sound_em_button_released = rospy.get_param("~sound_em_button_released", "button released")
73  self.sound_em_button_issued = rospy.get_param("~sound_em_button_issued", "button issued")
74  self.sound_em_brake_released = rospy.get_param("~sound_em_brake_released", "brake released")
75  self.sound_em_brake_issued = rospy.get_param("~sound_em_brake_issued", "brake issued")
76  self.sound_em_laser_released = rospy.get_param("~sound_em_laser_released", "laser released")
77  self.sound_em_laser_issued = rospy.get_param("~sound_em_laser_issued", "laser issued")
78  self.sound_em_wireless_released = rospy.get_param("~sound_em_wireless_released", "wireless released")
79  self.sound_em_wireless_issued = rospy.get_param("~sound_em_wireless_issued", "wireless issued")
80  self.sound_em_fall_released = rospy.get_param("~sound_em_fall_released", "fall released")
81  self.sound_em_fall_issued = rospy.get_param("~sound_em_fall_issued", "fall issued")
82  self.sound_em_internal_released = rospy.get_param("~sound_em_internal_released", "internal released")
83  self.sound_em_internal_issued = rospy.get_param("~sound_em_internal_issued", "internal issued")
84 
85  rospy.Subscriber("/diagnostics_agg", DiagnosticArray, self.diagnostics_agg_callback, queue_size=1)
86  self.em_state = EMState.EM_UNKNOWN
87 
88  self.diag_status = -1
89  if(self.diagnostics_based):
90  rospy.Subscriber("/diagnostics_toplevel_state", DiagnosticStatus, self.diagnostics_callback, queue_size=1)
91  self.last_diag = rospy.get_rostime()
92 
93  self.motion_status = -1
94  if(self.motion_based):
95  rospy.Subscriber("/joint_states", JointState, self.jointstate_callback, queue_size=1)
96  self.last_vel = rospy.get_rostime()
97 
98  self.pub_em_button_released = rospy.Publisher('em_button_released' , Empty, queue_size=1)
99  self.pub_brake_released = rospy.Publisher('brake_released' , Empty, queue_size=1)
100  self.pub_em_laser_released = rospy.Publisher('em_laser_released' , Empty, queue_size=1)
101  self.pub_em_wireless_released = rospy.Publisher('em_wireless_released', Empty, queue_size=1)
102  self.pub_em_fall_released = rospy.Publisher('em_fall_released' , Empty, queue_size=1)
103  self.pub_em_internal_released = rospy.Publisher('em_internal_released', Empty, queue_size=1)
104 
105  def diagnostics_agg_callback(self, msg):
106  diagnostics_errors = []
107  diagnostics_errors_detail = []
108 
109  #all diagnostics that have warning/error/stale
110  for status in msg.status:
111  if "Safety" in status.name:
112  if status.level > DiagnosticStatus.WARN:
113  diagnostics_errors.append(status)
114 
115  #reduce list to most detailed description only
116  for i, status in enumerate(diagnostics_errors):
117  tmp = diagnostics_errors[:i]+diagnostics_errors[i+1:]
118  if not next((True for status2 in tmp if status2.name.startswith(status.name)), False):
119  diagnostics_errors_detail.append(status)
120 
121  if not diagnostics_errors_detail:
122  if self.em_state > EMState.EM_FREE:
123  self.stop_light()
124  if self.em_state == EMState.EM_BUTTON:
125  self.pub_em_button_released.publish(Empty())
126  self.say(self.sound_em_button_released)
127  elif self.em_state == EMState.EM_BRAKE:
128  self.pub_brake_released.publish(Empty())
129  self.say(self.sound_em_brake_released)
130  elif self.em_state == EMState.EM_LASER:
131  self.pub_em_laser_released.publish(Empty())
132  self.say(self.sound_em_laser_released)
133  elif self.em_state == EMState.EM_WIRELESS:
134  self.pub_em_wireless_released.publish(Empty())
136  elif self.em_state == EMState.EM_FALL:
137  self.pub_em_fall_released.publish(Empty())
138  self.say(self.sound_em_fall_released)
139  elif self.em_state == EMState.EM_INTERNAL:
140  self.pub_em_internal_released.publish(Empty())
142  self.em_state = EMState.EM_FREE
143 
144  #determine error state
145  sound_output = ""
146  em_state = EMState.EM_UNKNOWN
147  for status in diagnostics_errors_detail:
148  if "Safety" in status.name:
149  for value in status.values:
150  if (value.key == "button_stop_ok"):
151  if (value.value == "False"):
152  if em_state <= EMState.EM_FREE or em_state > EMState.EM_BUTTON:
153  sound_output = self.sound_em_button_issued
154  em_state = EMState.EM_BUTTON
155  if (value.key == "brake_stop_ok"):
156  if (value.value == "False"):
157  if em_state <= EMState.EM_FREE or em_state > EMState.EM_BRAKE:
158  sound_output = self.sound_em_brake_issued
159  em_state = EMState.EM_BRAKE
160  if (value.key == "laser_stop_ok"):
161  if (value.value == "False"):
162  if em_state <= EMState.EM_FREE or em_state > EMState.EM_LASER:
163  sound_output = self.sound_em_laser_issued
164  em_state = EMState.EM_LASER
165  if (value.key == "wireless_stop_ok"):
166  if (value.value == "False"):
167  if em_state <= EMState.EM_FREE or em_state > EMState.EM_WIRELESS:
168  sound_output = self.sound_em_wireless_issued
169  em_state = EMState.EM_WIRELESS
170  if (value.key == "fall_sensor_front_ok"):
171  if (value.value == "False"):
172  if em_state <= EMState.EM_FREE or self.em_state > EMState.EM_FALL:
173  sound_output = self.sound_em_fall_issued
174  em_state = EMState.EM_FALL
175  if (value.key == "fall_sensor_left_ok"):
176  if (value.value == "False"):
177  if em_state <= EMState.EM_FREE or em_state > EMState.EM_FALL:
178  sound_output = self.sound_em_fall_issued
179  em_state = EMState.EM_FALL
180  if (value.key == "fall_sensor_right_ok"):
181  if (value.value == "False"):
182  if em_state <= EMState.EM_FREE or em_state > EMState.EM_FALL:
183  sound_output = self.sound_em_fall_issued
184  em_state = EMState.EM_FALL
185  if (value.key == "fall_sensors_released"):
186  if (value.value == "False"):
187  if em_state <= EMState.EM_FREE or em_state > EMState.EM_FALL:
188  sound_output = self.sound_em_fall_issued
189  em_state = EMState.EM_FALL
190  if (value.key == "efi_bus_front_io_error"):
191  if (value.value == "True"):
192  if em_state <= EMState.EM_FREE or em_state > EMState.EM_INTERNAL:
193  sound_output = self.sound_em_internal_issued
194  em_state = EMState.EM_INTERNAL
195  if (value.key == "efi_bus_left_io_error"):
196  if (value.value == "True"):
197  if em_state <= EMState.EM_FREE or em_state > EMState.EM_INTERNAL:
198  sound_output = self.sound_em_internal_issued
199  em_state = EMState.EM_INTERNAL
200  if (value.key == "efi_bus_right_io_error"):
201  if (value.value == "True"):
202  if em_state <= EMState.EM_FREE or em_state > EMState.EM_INTERNAL:
203  sound_output = self.sound_em_internal_issued
204  em_state = EMState.EM_INTERNAL
205 
206  rospy.logdebug("self.em_state: %d, em_state: %d"%(self.em_state, em_state))
207  if self.em_state != em_state and em_state > EMState.EM_FREE:
208  #emergency_stop_monitoring has higher priority
209  self.set_light(self.color_error)
210  self.say(sound_output)
211  self.em_state = em_state
212  rospy.logdebug("self.em_state: %d"%(self.em_state))
213 
214 
215  def diagnostics_callback(self, msg):
216  if self.em_state > EMState.EM_FREE:
217  #emergency_stop_monitoring has higher priority
218  return
219 
220  if self.diag_status != msg.level:
221  self.diag_status = msg.level
222  rospy.loginfo("Diagnostics change to "+ str(self.diag_status))
223 
224  if msg.level == DiagnosticStatus.OK:
225  self.stop_light()
226  self.motion_status = -1
227  else: # warning or error
228  self.set_light(self.color_warn)
229 
230 
231  def jointstate_callback(self, msg):
232  if self.em_state > EMState.EM_FREE:
233  #emergency_stop_monitoring has higher priority
234  return
235  if self.diag_status != DiagnosticStatus.OK:
236  #diagnostics_monitoring has higher priority
237  return
238 
239  threshold = 0.1
240  moving = 0
241  for v in msg.velocity:
242  if abs(v) > threshold:
243  moving = 1
244  break
245 
246  if self.motion_status != moving:
247  self.motion_status = moving
248  rospy.loginfo("Motion change to "+ str(self.motion_status))
249 
250  if moving == 0: # not moving
251  self.stop_light()
252  else: # moving
253  self.set_light(self.color_warn, True)
254 
255 
256 
257  def set_light(self, color, flashing=False):
258  if self.enable_light:
259  for component in self.light_components:
260  error_code, color_rgba = sss.compose_color(component, color)
261 
262  action_server_name = component + "/set_light"
263  client = actionlib.SimpleActionClient(action_server_name, SetLightModeAction)
264  # trying to connect to server
265  rospy.logdebug("waiting for %s action server to start",action_server_name)
266  if not client.wait_for_server(rospy.Duration(5)):
267  # error: server did not respond
268  rospy.logerr("%s action server not ready within timeout, aborting...", action_server_name)
269  else:
270  rospy.logdebug("%s action server ready",action_server_name)
271 
272  # sending goal
273  mode = LightMode()
274  mode.priority = 10
275  mode.colors = []
276  mode.colors.append(color_rgba)
277  if flashing:
278  mode.mode = LightModes.FLASH #Flashing
279  mode.frequency = 2.0 #Hz
280  else:
281  mode.mode = LightModes.GLOW #Glow
282  mode.frequency = 10.0 #Hz
283 
284  goal = SetLightModeGoal()
285  goal.mode = mode
286  client.send_goal(goal)
287  client.wait_for_result()
288  result = client.get_result()
289  self.track_id_light = result.track_id
290 
291  self.color = color
292  def stop_light(self):
293  if self.enable_light:
294  if self.track_id_light is not None:
295  for component in self.light_components:
296  srv_server_name = component + "/stop_mode"
297  try:
298  rospy.wait_for_service(srv_server_name, timeout=2)
299  srv_proxy = rospy.ServiceProxy(srv_server_name, StopLightMode)
300  req = StopLightModeRequest()
301  req.track_id = self.track_id_light
302  srv_proxy(req)
303  except Exception as e:
304  rospy.logerr("%s service failed: %s",srv_server_name, e)
305 
306  def say(self, text):
307  if self.enable_sound and text:
308  for component in self.sound_components:
309  sss.say(component, [text])
310 
311 if __name__ == "__main__":
312  rospy.init_node("emergency_stop_monitor")
314  rospy.spin()
def diagnostics_callback(self, msg)
Diagnostics monitoring.
def jointstate_callback(self, msg)
Motion Monitoring.
def set_light(self, color, flashing=False)
set light


cob_monitoring
Author(s): Florian Weisshardt , Felix Messmer
autogenerated on Tue May 2 2023 02:26:09