chronologic_state.py
Go to the documentation of this file.
00001 # Software License Agreement (BSD License)
00002 #
00003 # Copyright (c) 2012, Willow Garage, Inc.
00004 # All rights reserved.
00005 #
00006 # Redistribution and use in source and binary forms, with or without
00007 # modification, are permitted provided that the following conditions
00008 # are met:
00009 #
00010 #  * Redistributions of source code must retain the above copyright
00011 #    notice, this list of conditions and the following disclaimer.
00012 #  * Redistributions in binary form must reproduce the above
00013 #    copyright notice, this list of conditions and the following
00014 #    disclaimer in the documentation and/or other materials provided
00015 #    with the distribution.
00016 #  * Neither the name of Willow Garage, Inc. nor the names of its
00017 #    contributors may be used to endorse or promote products derived
00018 #    from this software without specific prior written permission.
00019 #
00020 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
00021 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00022 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
00023 # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
00024 # COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
00025 # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
00026 # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00027 # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
00028 # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00029 # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
00030 # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00031 # POSSIBILITY OF SUCH DAMAGE.
00032 #
00033 # Author: Isaac Saito, Ze'ev Klapow
00034 
00035 from diagnostic_msgs.msg import DiagnosticArray, DiagnosticStatus
00036 from python_qt_binding.QtGui import QTreeWidgetItem
00037 import rospy
00038 
00039 from .inspector_window import InspectorWindow
00040 from .util_robot_monitor import Util
00041 
00042 
00043 class StatusItem(QTreeWidgetItem):
00044     """
00045     Represents a single tree node that is capable of holding children objects
00046     of its class type.
00047     """
00048 
00049     def __init__(self, status):
00050         """
00051         :type status: DiagnosticStatus
00052         """
00053         super(StatusItem, self).__init__(QTreeWidgetItem.UserType)
00054 
00055         self._children_statusitems = []
00056         self.name = status.name
00057         self.level = status.level
00058         self.last_level = None
00059         self.inspector = None
00060         self.status = status  # DiagnosticsStatus
00061 
00062         self.warning_id = None
00063         self.error_id = None
00064 
00065         self.setText(0, '/' + Util.get_grn_resource_name(self.name))
00066 
00067     def get_name(self):
00068         return self.name
00069 
00070     def enable(self):
00071         if self.inspector:
00072             self.inspector.enable()
00073 
00074     def disable(self):
00075         if self.inspector:
00076             self.inspector.disable()
00077 
00078     def update(self, status):
00079         """
00080         Replace old status with the passed one.
00081 
00082         :type status: DiagnosticsStatus
00083         """
00084         self.status = status
00085 
00086     def update_children(self, status_new, diag_array):
00087         """
00088 
00089         Recursive for tree node's children.
00090         Update text on treeWidgetItem, set icon on it.
00091 
00092         :type status: DiagnosticStatus
00093         :type msg: DiagnosticArray
00094         """
00095 
00096         self.status = status_new
00097 
00098         if self.inspector:
00099             self.inspector.update_status_display(self.status)
00100 
00101         children_diag_statuses = Util.get_children(self.name, diag_array)
00102 
00103         names_toplevel_local = [s.name for s in self._children_statusitems]
00104         errors = 0
00105         warnings = 0
00106         for child_diagnostic_status in children_diag_statuses:
00107             name = child_diagnostic_status.name
00108             device_name = Util.get_grn_resource_name(
00109                                                   child_diagnostic_status.name)
00110             if (child_diagnostic_status.level != DiagnosticStatus.OK):
00111                 Util.gen_headline_warn_or_err(
00112                                                        child_diagnostic_status)
00113                 if (child_diagnostic_status.level == DiagnosticStatus.ERROR):
00114                     errors = errors + 1
00115                 elif (child_diagnostic_status.level == DiagnosticStatus.WARN):
00116                     warnings = warnings + 1
00117             else:
00118                 Util.gen_headline_status_green(child_diagnostic_status)
00119             rospy.logdebug(' update_children level= %s',
00120                            child_diagnostic_status.level)
00121 
00122             if name in names_toplevel_local:
00123                 index_child = names_toplevel_local.index(name)
00124                 status_item = self._children_statusitems[index_child]
00125                 # Recursive call.
00126                 status_item.update_children(
00127                                            child_diagnostic_status, diag_array)
00128                 Util.update_status_images(child_diagnostic_status, status_item)
00129                 rospy.logdebug(' StatusItem update 33 index= %d dev_name= %s',
00130                                index_child, device_name)
00131                 status_item.setText(0, device_name)
00132                 status_item.setText(1, child_diagnostic_status.message)
00133             elif len(self.strip_child(name).split('/')) <= 2:
00134                 status_item = StatusItem(child_diagnostic_status)
00135                 # Recursive call.
00136                 status_item.update_children(child_diagnostic_status,
00137                                             diag_array)
00138                 status_item.setText(0, device_name)
00139                 status_item.setText(1, child_diagnostic_status.message)
00140                 self._children_statusitems.append(status_item)
00141                 self.addChild(status_item)
00142 
00143         rospy.logdebug(' ------ Statusitem.update_children err=%d warn=%d',
00144                        errors, warnings)
00145         return {Util._DICTKEY_TIMES_ERROR: errors,
00146                 Util._DICTKEY_TIMES_WARN: warnings}
00147 
00148     def on_click(self):
00149         if not self.inspector:
00150             self.inspector = InspectorWindow(self.status,
00151                                              self.close_inspector_window)
00152         else:
00153             self.inspector.activateWindow()
00154 
00155     def close_inspector_window(self):
00156         rospy.logdebug(' ------ Statusitem close_inspector_window 1')
00157         self.inspector = None
00158 
00159     def strip_child(self, child):
00160         return child.replace(self.name, '')
00161 
00162     def close(self):
00163         """
00164         Because Isaac failed to find a way to call a destructor of a class in
00165         python in general, he made this function, intending it to be called by
00166         its parent object (in this case RobotMonitorWidget's instance)
00167         every timeline when a certain node gets removed.
00168         """
00169         if self.inspector:
00170             # del self.inspector # This doesn't _close the window
00171             self.inspector.close()
00172 
00173         # _close children.
00174         for status_item in self._children_statusitems:
00175             status_item.close()
00176 
00177 
00178 class InstantaneousState(object):
00179     """
00180     A container for StatusItem per timeframe (second).
00181 
00182     Copied from robot_monitor.
00183     """
00184     def __init__(self):
00185         self._items = {}  # dict of StatusItem
00186         self._msg = None
00187         self._has_warned_no_name = False
00188 
00189     def reset(self):
00190         self._items = {}
00191         self._msg = None
00192 
00193     def get_descendants(self, item):
00194         rospy.logdebug(' Status get_descendants status.name=%s',
00195                        item.status.name)
00196         child_keys = [k for k in self._items.iterkeys()
00197                       if k.startswith(item.status.name + "/")]
00198         children = [self._items[k] for k in child_keys]
00199         return children
00200 
00201     def get_items(self):
00202         return self._items
00203 
00204     def update(self, msg):
00205         """
00206 
00207         :type msg: DiagnosticArray
00208         """
00209         removed = []
00210         added = []
00211         items = {}
00212 
00213         # fill items from new msg, creating new StatusItems for any that don't
00214         # already exist, and keeping track of those that have been added new
00215         for s in msg.status:
00216             # DiagnosticStatus messages without a name are invalid #3806
00217             if not s.name and not self._has_warned_no_name:
00218                 rospy.logwarn('DiagnosticStatus message with no "name". ' +
00219                               'Unable to add to robot monitor. Message: ' +
00220                               '%s, hardware ID: %s, level: %d' %
00221                               (s.message, s.hardware_id, s.level))
00222                 self._has_warned_no_name = True
00223 
00224             if not s.name:
00225                 continue
00226 
00227             if (len(s.name) > 0 and s.name[0] != '/'):
00228                 s.name = '/' + s.name
00229 
00230             if (s.name not in self._items):
00231                 i = StatusItem(s)
00232                 added.append(i)
00233                 items[s.name] = i
00234             else:
00235                 i = self._items[s.name]
00236                 i.update(s)
00237                 items[s.name] = i
00238 
00239         # find anything without a parent already in the items, and add it as a
00240         # dummy item
00241         to_add = []
00242         dummy_names = []
00243         for i in items.itervalues():
00244             parent = i.status.name
00245             while (len(parent) != 0):
00246                 parent = Util.get_parent_name(parent)
00247                 if (len(parent) > 0 and
00248                     (parent not in items) and
00249                     parent not in dummy_names):
00250 
00251                     pi = None
00252                     if (parent not in self._items):
00253                         s = DiagnosticStatus()
00254                         s.name = parent
00255                         s.message = ""
00256                         pi = StatusItem(s)
00257                     else:
00258                         pi = self._items[parent]
00259 
00260                     to_add.append(pi)
00261                     dummy_names.append(pi.status.name)
00262 
00263         for a in to_add:
00264             if (a.status.name not in items):
00265                 items[a.status.name] = a
00266 
00267                 if (a.status.name not in self._items):
00268                     added.append(a)
00269 
00270         for i in self._items.itervalues():
00271             # determine removed items
00272             if (i.status.name not in items):
00273                 removed.append(i)
00274 
00275         # remove removed items
00276         for r in removed:
00277             del self._items[r.status.name]
00278 
00279         self._items = items
00280         self._msg = msg
00281 
00282         # sort so that parents are always added before children
00283         added.sort(cmp=lambda l, r: cmp(l.status.name, r.status.name))
00284         # sort so that children are always removed before parents
00285         removed.sort(cmp=lambda l,
00286                      r: cmp(l.status.name, r.status.name),
00287                      reverse=True)
00288 
00289         return (added, removed, self._items)


rqt_robot_monitor
Author(s): Isaac Saito, Ze'ev Klapow, Kevin Watts, Josh Faust
autogenerated on Mon Oct 6 2014 07:16:09