util_robot_monitor.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 import os
00036 import copy
00037 
00038 import roslib;roslib.load_manifest('rqt_robot_monitor')
00039 import rospy
00040 from diagnostic_msgs.msg import DiagnosticStatus
00041 from python_qt_binding.QtGui import QColor, QIcon
00042 
00043 class Util(object):
00044     """
00045     
00046     @todo: Utils and common configs are mixed in this class.
00047     """
00048     
00049     _SECONDS_TIMELINE = 30
00050     
00051     # Instantiating icons that show the device status.
00052     _ERR_ICON = QIcon.fromTheme('dialog-error')  # 'face-angry')
00053     _WARN_ICON = QIcon.fromTheme('dialog-warning')  # 'face-sick')
00054     _OK_ICON = QIcon.fromTheme('emblem-default')  # 'face-laugh')
00055     # Added following this QA thread http://goo.gl/83tVZ  
00056     _STALE_ICON = QIcon.fromTheme('dialog-question')  # 'face-tired')
00057       
00058     _IMG_DICT = {0: _OK_ICON, 1: _WARN_ICON, 2: _ERR_ICON, 3: _STALE_ICON}
00059     
00060     _COLOR_DICT = {0: QColor(85, 178, 76),
00061                    1: QColor(222, 213, 17),
00062                    2: QColor(178, 23, 46),
00063                    3: QColor(40, 23, 176)
00064                    }
00065     # DiagnosticStatus dosn't have Stale status. Related QA:http://goo.gl/83tVZ
00066     # It's not ideal to add STALE to DiagnosticStatus as you see in that thread,
00067     # but here this addition is only temporary for the purpose of implementation
00068     # simplicity.  
00069     DiagnosticStatus.STALE = 3
00070     
00071     _DICTKEY_TIMES_ERROR = 'times_errors'
00072     _DICTKEY_TIMES_WARN = 'times_warnings'
00073     _DICTKEY_INDEX = 'index'
00074     _DICTKEY_STATITEM = 'statitem'
00075 
00076     
00077     def __init__(self):
00078         super(Util, self).__init__()
00079     
00080     @staticmethod
00081     def _update_status_images(diagnostic_status, statusitem):
00082         """
00083         Taken from robot_monitor.robot_monitor_panel.py.
00084         
00085         @param status: DiagnosticStatus         
00086         @param node: StatusItem 
00087         @author: Isaac Saito 
00088         """
00089 
00090         name = diagnostic_status.name
00091         if (name is not None):
00092             # level = diagnosis_status.level
00093             level = diagnostic_status.level                
00094             rospy.logdebug('New diagnostic_status level: %s. Last lv: %s name: %s',
00095                        level, statusitem.last_level, name)        
00096             if (diagnostic_status.level != statusitem.last_level):  
00097                 # TODO Apparently diagnosis_status doesn't contain last_level. 
00098                 statusitem.setIcon(0, Util._IMG_DICT[level])
00099                 statusitem.last_level = level
00100                 return
00101                
00102     '''
00103     @param param: status_name is a string that may consists of status names that 
00104                   are delimited by slash.   
00105     @return: string
00106     '''
00107     @staticmethod
00108     def get_nice_name(status_name):
00109         name = status_name.split('/')[-1]
00110         rospy.logdebug(' get_nice_name name = %s', name)
00111         return name
00112     
00113     @staticmethod
00114     def remove_parent_name(status_name):
00115         return ('/'.join(status_name.split('/')[2:])).strip()
00116     
00117     @staticmethod
00118     def get_parent_name(status_name):
00119         return ('/'.join(status_name.split('/')[:-1])).strip()
00120     
00121     @staticmethod
00122     def gen_headline_status_green(diagnostic_status):
00123         # return "%s : %s" % (get_nice_name(diagnostic_status.status.name), 
00124         #                                   diagnostic_status.status.message)
00125         return "%s" % Util.get_nice_name(diagnostic_status.name)
00126     
00127     @staticmethod
00128     def gen_headline_warn_or_err(diagnostic_status):
00129         return "%s : %s" % (Util.get_nice_name(diagnostic_status.name),
00130                             diagnostic_status.message)
00131 
00132     @staticmethod
00133     def _get_color_for_message(msg, mode = 0):
00134         """ 
00135         
00136         @param msg: Either DiagnosticArray or DiagnosticsStatus.
00137         @param mode: int. When 0, this func will iterate msg to find 
00138                      DiagnosticsStatus.level and put it into a dict.
00139                      When 1, this func finds DiagnosticsStatus.level from msg
00140                      without iteration (thus, msg is expected to be
00141                      DiagnosticsStatus instance). 
00142          
00143         Copied from robot_monitor.
00144         """
00145                 
00146         level = 0
00147         min_level = 255
00148         
00149         lookup = {}
00150         for status in msg.status:
00151             lookup[status.name] = status
00152             
00153         names = [status.name for status in msg.status]
00154         names = [name for name in names if len(Util.get_parent_name(name)) == 0]
00155         for name in names:
00156             status = lookup[name]
00157             if (status.level > level):
00158                 level = status.level
00159             if (status.level < min_level):
00160                 min_level = status.level
00161 
00162         # Stale items should be reported as errors unless all stale
00163         if (level > 2 and min_level <= 2):
00164             level = 2
00165                 
00166         #return Util._IMG_DICT[level]
00167         rospy.logdebug(' get_color_for_message color lv=%d', level)
00168         return Util._COLOR_DICT[level]
00169     
00170     @staticmethod
00171     def get_correspondent(key, list_statitem):
00172         """
00173         
00174         @param key: String.  
00175         @param list_statitem: DiagnosticsStatus
00176         @return: StatusItem
00177         """
00178         names_from_list = [Util.get_nice_name(k.name) for k in list_statitem]
00179         key_niced = Util.get_nice_name(key)
00180         index_key = -1        
00181         statitem_key = None
00182         if key_niced in names_from_list:
00183             index_key = names_from_list.index(key_niced)
00184             statitem_key = list_statitem[index_key]
00185             rospy.logdebug(' get_correspondent index_key=%s statitem_key=%s',
00186                           index_key, statitem_key)
00187         return {Util._DICTKEY_INDEX : index_key,
00188                 Util._DICTKEY_STATITEM : statitem_key}
00189 
00190     @staticmethod
00191     def get_correspondent_index(key, statusitems):
00192         """
00193         @deprecated: Use get_correspondent
00194         
00195         @param key: string
00196         @param statusitems: DiagnosticStatus[]
00197         @return: int of index that key is found in array. -1 if not found
00198         """
00199 
00200         names = [Util.get_nice_name(k.name) for k in statusitems]
00201         
00202         rospy.logdebug('\tget_correspondent_index len of names=%d statusitems=%d',
00203                        len(names), len(statusitems))
00204         
00205         if key in names:
00206             rospy.logdebug(' get_correspondent_index key IS contained.')
00207             return names.index(key)
00208         else:
00209             rospy.logdebug('** get_correspondent_index key IS NOT contained.')
00210             return -1 
00211 
00212     @staticmethod
00213     def get_children(name, diag_array):
00214         """
00215         
00216         @param msg: DiagnosticArray
00217         @return: DiagnosticStatus[]
00218         """
00219         
00220         ret = []
00221         for k in diag_array.status:  # k is DiagnosticStatus. 
00222             if k.name.startswith(name):  # Starting with self.name means k 
00223                                        # is either top/parent node or its child.
00224                 if not k.name == name:  # Child's name must be different 
00225                                             # from that of the top/parent node.  
00226                     ret.append(k)
00227         return ret      


rqt_robot_monitor
Author(s): Isaac Saito, Ze'ev Klapow
autogenerated on Fri Jan 3 2014 11:56:17