diagnostic_gui.py
Go to the documentation of this file.
00001 #!/usr/bin/env python
00002 
00003 # Software License Agreement (BSD License)
00004 #
00005 # Copyright (c) 2014-2017, Dataspeed Inc.
00006 # All rights reserved.
00007 #
00008 # Redistribution and use in source and binary forms, with or without modification,
00009 # are permitted provided that the following conditions are met:
00010 # 
00011 #     * Redistributions of source code must retain the above copyright notice,
00012 #       this list of conditions and the following disclaimer.
00013 #     * Redistributions in binary form must reproduce the above copyright notice,
00014 #       this list of conditions and the following disclaimer in the documentation
00015 #       and/or other materials provided with the distribution.
00016 #     * Neither the name of Dataspeed Inc. nor the names of its
00017 #       contributors may be used to endorse or promote products derived from this
00018 #       software without specific prior written permission.
00019 #
00020 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
00021 # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
00022 # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
00023 # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
00024 # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
00025 # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
00026 # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
00027 # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
00028 # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
00029 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00030 
00031 import os
00032 import rospy
00033 import rospkg
00034 import time
00035 
00036 from qt_gui.plugin import Plugin
00037 from python_qt_binding import loadUi
00038 from python_qt_binding.QtWidgets import QWidget, QGraphicsScene, QLabel, QGraphicsEllipseItem, QGraphicsLineItem, QGraphicsTextItem
00039 from python_qt_binding.QtCore import Qt, Signal, QTimer, QDateTime, QDate, QTime, QPoint
00040 from python_qt_binding.QtGui import QPixmap, QFont, QPen, QColor, QBrush, QImage
00041     
00042 from cmath import *
00043 from math import *
00044 
00045 from mobility_base_core_msgs.msg import Mode, JoystickRaw
00046 from rospy.rostime import Time
00047 from geometry_msgs.msg import Twist
00048 
00049 from mobility_base_core_msgs.msg import BumperState
00050 from mobility_base_core_msgs.msg import BatteryState
00051 from sensor_msgs.msg import Imu
00052 import std_msgs.msg
00053 import std_srvs.srv
00054 from mobility_base_core_msgs.srv import GetMaxSpeed, SetMaxSpeed
00055 from numpy import isfinite
00056 from mobility_base_core_msgs.srv import SetMaxSpeedRequest
00057 
00058 
00059 class BumperIndex:
00060     def __init__(self):
00061         pass
00062 
00063     BUMPER_1F = 0
00064     BUMPER_1L = 1
00065     BUMPER_1R = 2
00066     BUMPER_1B = 3
00067     
00068     BUMPER_2F = 4
00069     BUMPER_2L = 5
00070     BUMPER_2R = 6
00071     BUMPER_2B = 7
00072     
00073     BUMPER_3F = 8
00074     BUMPER_3L = 9
00075     BUMPER_3R = 10
00076     BUMPER_3B = 11
00077     
00078     BUMPER_4F = 12
00079     BUMPER_4L = 13
00080     BUMPER_4R = 14
00081     BUMPER_4B = 15    
00082 
00083 
00084 class ChannelIndex:
00085     def __init__(self):
00086         pass
00087 
00088     CHAN_ENABLE = 0
00089     CHAN_ROTATE = 1
00090     CHAN_FORWARD = 2
00091     CHAN_LATERAL = 3
00092     CHAN_MODE = 4
00093     CHAN_EXTRA = 5       
00094 
00095 
00096 class DiagnosticGui(Plugin):
00097     last_suppress_time = Time()
00098     last_twist_time = Time()
00099     gui_update_timer = QTimer()
00100     
00101     # Raw joystick data    
00102     joystick_data = []
00103     joystick_table_vals = []
00104     joystick_channel_text = ['CHAN_ENABLE: ', 'CHAN_ROTATE: ', 'CHAN_FORWARD: ', 'CHAN_LATERAL: ', 'CHAN_MODE: ', 'CHAN_EXTRA: ']
00105     joystick_bind_status = False
00106     joystick_bind_dot_counter = 0
00107     
00108     # Mode
00109     current_mode = -1
00110     
00111     # Topic pub timeouts    
00112     JOYSTICK_SUPPRESS_PERIOD = 0.2  # 5 Hz
00113     CMD_VEL_TIMEOUT_PERIOD = 0.2    # 5 Hz
00114     joystick_suppressed = False
00115     command_received = False
00116     current_cmd = Twist()
00117     battery_percent = 0
00118     battery_voltage = 0
00119     
00120     # Checklist icons
00121     bad_icon = QPixmap()
00122     good_icon = QPixmap()
00123     none_icon = QPixmap()
00124     
00125     # Checklist status
00126     GOOD = 0
00127     BAD = 1
00128     NONE = 2
00129     
00130     # Checklist variables
00131     checklist_status = []
00132     
00133     BATT_MAN = 0
00134     ESTOP_MAN = 1
00135     DISABLE_MAN = 2
00136     JOYSTICK_MAN = 3
00137     SUPPRESS_MAN = 4    
00138     BATT_COMP = 5
00139     ESTOP_COMP = 6
00140     DISABLE_COMP = 7
00141     JOYSTICK_COMP = 8
00142     SUPPRESS_COMP = 9
00143     CMD_COMP = 10
00144     
00145     # Bumpers
00146     bumper_front_left = 0
00147     bumper_front_right = 0
00148     bumper_rear_left = 0
00149     bumper_rear_right = 0
00150     
00151     # Gyro cal
00152     gyro_cal_status = False
00153     gyro_x = 0.0
00154     gyro_y = 0.0
00155     gyro_z = 0.0
00156     cal_enabled = True
00157     cal_time = rospy.Time(0)
00158     
00159     # Max speed config
00160     max_speed_known = False
00161     max_speed_dirty = True
00162     max_linear_actual = 0.0
00163     max_angular_actual = 0.0
00164     max_linear_setting = 0.0
00165     max_angular_setting = 0.0
00166     
00167     # Wake time
00168     current_wake_time = rospy.Time(0)
00169     rel_wake_days = 0
00170     rel_wake_hours = 0
00171     rel_wake_minutes = 0
00172     rel_wake_secs = 0
00173     
00174     # Switching between tabs and full GUI
00175     is_currently_tab = False
00176     widget_count = 0
00177     current_tab_idx = -1
00178     raw_data_tab_idx = 5
00179     
00180     # Check connection to base
00181     base_connected = False
00182     last_joystick_time = rospy.Time(0)
00183     
00184     # Constants    
00185     stick_ind_lox = 80
00186     stick_ind_loy = 136
00187     stick_ind_rox = 286
00188     stick_ind_roy = 135
00189     stick_ind_range_pix = 88.0
00190     stick_ind_range_max = JoystickRaw.MAX
00191     stick_ind_range_min = JoystickRaw.MIN
00192     stick_ind_range_mid = JoystickRaw.CENTER
00193     stick_ind_range_factor = stick_ind_range_pix / (stick_ind_range_max - stick_ind_range_min)
00194     stick_ind_radius = 7    
00195     mode_ind_x1 = 52
00196     mode_ind_y1 = 37
00197     mode_ind_x2 = 44
00198     mode_ind_y2 = 13
00199     power_ind_x1 = 160
00200     power_ind_x2 = 206
00201     power_ind_y = 213    
00202     bumper_fl_x = 70
00203     bumper_fl_y = 60
00204     bumper_fr_x = 293
00205     bumper_fr_y = 60
00206     bumper_rl_x = 70
00207     bumper_rl_y = 282
00208     bumper_rr_x = 293
00209     bumper_rr_y = 282
00210     bumper_dx = 62
00211     bumper_dy = 54    
00212     joystick_table_left_edge = 440
00213     joystick_table_top_edge = 525    
00214     twist_table_left_edge = 700
00215     twist_table_top_edge = 580    
00216     battery_table_left_edge = 700
00217     battery_table_top_edge = 730
00218 
00219     _deferred_fit_in_view = Signal()
00220     
00221     def __init__(self, context):
00222         super(DiagnosticGui, self).__init__(context)
00223 
00224         # Qt setup
00225         self.context_ = context
00226         self.init_gui('full')
00227         
00228         # ROS setup
00229         self.topic_timeout_timer = rospy.Timer(rospy.Duration(0.02), self.topic_timeout_cb)
00230         self.subscribe_topics()
00231         self.advertise_topics()
00232         
00233     def init_gui(self, gui_type):
00234         if gui_type == 'full':
00235             self.spawn_full_gui()
00236             self.init_tables(self._widget, self.joystick_table_left_edge, self.joystick_table_top_edge)
00237         else:
00238             self.spawn_tab_gui()
00239             self.init_tables(self._widget.gui_tabs.widget(self.raw_data_tab_idx), 20, 20)
00240             self._widget.gui_tabs.setCurrentIndex(self.current_tab_idx)
00241             
00242         self.reset_gui_timer()
00243         self.init_joystick_graphics()
00244         self.init_bumper_graphics()
00245         self.init_checklists()
00246         self.bind_callbacks()
00247         self.refresh_max_speed()
00248         
00249         # Initialize absolute wake time setter to current time
00250         datetime_now = QDateTime(QDate.currentDate(), QTime.currentTime())
00251         self._widget.absolute_wake_time_obj.setDateTime(datetime_now)
00252         temp_time = self._widget.absolute_wake_time_obj.time()
00253         temp_time = QTime(temp_time.hour(), temp_time.minute())
00254         self._widget.absolute_wake_time_obj.setTime(temp_time)
00255         
00256         # Set connection label text
00257         if self.base_connected:
00258             self._widget.disconnected_lbl.setVisible(False)
00259         else:
00260             self._widget.disconnected_lbl.setVisible(True)
00261             self._widget.disconnected_lbl.setText('<font color=#FF0000>NOT CONNECTED</font>')
00262 
00263     def topic_timeout_cb(self, event):
00264         # Joystick suppression
00265         if (event.current_real - self.last_suppress_time).to_sec() < self.JOYSTICK_SUPPRESS_PERIOD and self.suppress_dt.to_sec() <= 1.0/9.0:
00266             self.joystick_suppressed = True
00267         else:
00268             self.joystick_suppressed = False
00269             
00270         # Command message
00271         if (event.current_real - self.last_twist_time).to_sec() < self.CMD_VEL_TIMEOUT_PERIOD and self.twist_dt.to_sec() <= 1.0/6.0:
00272             self.command_received = True
00273         else:
00274             self.command_received = False
00275 
00276     def init_checklists(self):
00277         self.bad_icon.load(os.path.join(rospkg.RosPack().get_path('mobility_base_tools'), 'images', 'bad.png'))
00278         self.good_icon.load(os.path.join(rospkg.RosPack().get_path('mobility_base_tools'), 'images', 'good.png'))
00279         self.none_icon.load(os.path.join(rospkg.RosPack().get_path('mobility_base_tools'), 'images', 'none.png'))        
00280         self.checklist_status=[0 for i in range(self.CMD_COMP + 1)]
00281         self.checklist_status[self.BATT_MAN] = self.NONE
00282         self.checklist_status[self.ESTOP_MAN] = self.NONE
00283         self.checklist_status[self.DISABLE_MAN] = self.NONE
00284         self.checklist_status[self.JOYSTICK_MAN] = self.NONE
00285         self.checklist_status[self.SUPPRESS_MAN] = self.NONE        
00286         self.checklist_status[self.BATT_COMP] = self.NONE
00287         self.checklist_status[self.ESTOP_COMP] = self.NONE
00288         self.checklist_status[self.DISABLE_COMP] = self.NONE
00289         self.checklist_status[self.JOYSTICK_COMP] = self.NONE
00290         self.checklist_status[self.SUPPRESS_COMP] = self.NONE
00291         self.checklist_status[self.CMD_COMP] = self.NONE
00292 
00293     def init_tab_tables(self):
00294         self.joystick_table_vals = [QLabel(self._widget.gui_tabs.widget(self.raw_data_tab_idx)) for i in range(ChannelIndex.CHAN_EXTRA+1)]
00295         self.joystick_table_labels = [QLabel(self._widget.gui_tabs.widget(self.raw_data_tab_idx)) for i in range(ChannelIndex.CHAN_EXTRA+1)]
00296         self.joystick_table_heading = QLabel(self._widget.gui_tabs.widget(self.raw_data_tab_idx))
00297         
00298     def init_tables(self, widget, left, top):
00299         # Joystick data table
00300         self.joystick_data = [0 for i in range(ChannelIndex.CHAN_EXTRA+1)]
00301         self.joystick_table_vals = [QLabel(widget) for i in range(ChannelIndex.CHAN_EXTRA+1)]
00302         self.joystick_table_labels = [QLabel(widget) for i in range(ChannelIndex.CHAN_EXTRA+1)]
00303         self.joystick_table_heading = QLabel(widget)
00304         
00305         self.joystick_table_heading.setText('Raw Joystick Data')
00306         self.joystick_table_heading.setFont(QFont('Ubuntu', 11, QFont.Bold))
00307         self.joystick_table_heading.move(left, top)
00308         for i in range(len(self.joystick_table_vals)):
00309             self.joystick_table_vals[i].move(left + 150, top + 30 * (i+1))
00310             self.joystick_table_vals[i].setText('0000')
00311             self.joystick_table_vals[i].setFixedWidth(200)
00312             
00313             self.joystick_table_labels[i].move(left, top + 30 * (i+1))
00314             self.joystick_table_labels[i].setText(self.joystick_channel_text[i])
00315             
00316         # Twist data table
00317         self.twist_table_heading = QLabel(widget)
00318         self.twist_table_heading.setText('Current Twist Command')
00319         self.twist_table_heading.setFont(QFont('Ubuntu', 11, QFont.Bold))
00320         self.twist_table_heading.move(left + 260, top)
00321         self.twist_table_labels = [QLabel(widget) for i in range(0, 3)]
00322         self.twist_table_vals = [QLabel(widget) for i in range(0, 3)]
00323         for i in range(len(self.twist_table_vals)):
00324             self.twist_table_vals[i].move(left + 260 + 150, top + 30 * (i+1))
00325             self.twist_table_vals[i].setText('Not Published')
00326             self.twist_table_vals[i].setFixedWidth(200)
00327             self.twist_table_labels[i].move(left + 260, top + 30 * (i+1))
00328             
00329         self.twist_table_labels[0].setText('Forward (m/s):')
00330         self.twist_table_labels[1].setText('Lateral (m/s):')
00331         self.twist_table_labels[2].setText('Rotation (rad/s):')
00332         
00333         # Battery percentage
00334         self.battery_heading = QLabel(widget)
00335         self.battery_heading.setText('Current Battery State')
00336         self.battery_heading.setFont(QFont('Ubuntu', 11, QFont.Bold))
00337         self.battery_heading.move(left + 260, top + 150)
00338         self.battery_label = QLabel(widget)
00339         self.battery_label.move(left + 260, top + 150 +30)
00340         self.battery_label.setText('000 %')
00341         self.battery_voltage_label = QLabel(widget)
00342         self.battery_voltage_label.move(left + 260, top + 150 +60)
00343         self.battery_voltage_label.setText('00.00 V')
00344         self.battery_voltage_label.setFixedWidth(200)
00345         
00346         # Mode
00347         self.mode_heading = QLabel(widget)
00348         self.mode_heading.setFont(QFont('Ubuntu', 11, QFont.Bold))
00349         self.mode_heading.move(left, top + 225)
00350         self.mode_heading.setText('Current Mode')
00351         self.mode_label = QLabel(widget)
00352         self.mode_label.move(left + 120, top + 225)        
00353         self.mode_label.setText('XXXXXXXXXXXXXXXXXXXXXX')
00354 
00355     def bind_callbacks(self):
00356         self._widget.start_bind_btn.clicked.connect(self.start_bind)
00357         self._widget.stop_bind_btn.clicked.connect(self.stop_bind)
00358         
00359         self._widget.gyro_cal_btn.clicked.connect(self.cal_gyro)
00360         self._widget.clear_cal_btn.clicked.connect(self.clear_cal)
00361         
00362         self._widget.max_linear_txt.editingFinished.connect(self.max_linear_changed)
00363         self._widget.max_angular_txt.editingFinished.connect(self.max_angular_changed)
00364         self._widget.set_speed_btn.clicked.connect(self.set_max_speed)
00365         self._widget.clear_speed_btn.clicked.connect(self.clear_max_speed)
00366         
00367         self._widget.wake_time_days_txt.editingFinished.connect(self.wake_days_changed)
00368         self._widget.wake_time_hours_txt.editingFinished.connect(self.wake_hours_changed)
00369         self._widget.wake_time_minutes_txt.editingFinished.connect(self.wake_minutes_changed)
00370         self._widget.wake_time_secs_txt.editingFinished.connect(self.wake_secs_changed)
00371         self._widget.set_relative_wake_time_btn.clicked.connect(self.set_relative_wake_time)
00372         self._widget.set_absolute_wake_time_btn.clicked.connect(self.set_absolute_wake_time)
00373         self._widget.clear_wake_time_btn.clicked.connect(self.clear_wake_time)
00374         
00375         if self.is_currently_tab:
00376             self._widget.gui_tabs.currentChanged.connect(self.set_current_tab)
00377         
00378     def set_current_tab(self, idx):
00379         self.current_tab_idx = self._widget.gui_tabs.currentIndex()
00380         
00381     def start_bind(self):
00382         self.pub_start_bind.publish(std_msgs.msg.Empty())
00383         
00384     def stop_bind(self):
00385         self.pub_stop_bind.publish(std_msgs.msg.Empty())
00386         
00387     def cal_gyro(self):
00388         gyro_cal_srv = rospy.ServiceProxy('/mobility_base/imu/calibrate', std_srvs.srv.Empty)
00389         try:
00390             gyro_cal_srv()
00391             self.cal_enabled = False
00392             self.cal_time = rospy.Time.now()
00393         except:
00394             pass
00395  
00396     def clear_cal(self):
00397         clear_cal_srv = rospy.ServiceProxy('/mobility_base/imu/clear_cal', std_srvs.srv.Empty)
00398         try:
00399             clear_cal_srv()
00400         except:
00401             pass
00402         
00403     def max_linear_changed(self):
00404         try:
00405             float_val = float(self._widget.max_linear_txt.text())
00406             self.max_linear_setting = float_val;
00407         except ValueError:
00408             if self.max_linear_actual <= 0 or not isfinite(self.max_linear_actual):
00409                 self.max_linear_setting = 0.0
00410             else:
00411                 self.max_linear_setting = self.max_linear_actual
00412         self.max_speed_dirty = True
00413         
00414     def max_angular_changed(self):
00415         try:
00416             float_val = float(self._widget.max_angular_txt.text())
00417             self.max_angular_setting = float_val;
00418         except ValueError:
00419             if self.max_angular_actual <= 0 or not isfinite(self.max_angular_actual):
00420                 self.max_angular_setting = 0.0
00421             else:
00422                 self.max_angular_setting = self.max_angular_actual
00423         self.max_speed_dirty = True
00424         
00425     def set_max_speed(self):
00426         set_max_speed_srv = rospy.ServiceProxy('/mobility_base/set_max_speed', SetMaxSpeed)
00427         req = SetMaxSpeedRequest()
00428         req.linear = self.max_linear_setting
00429         req.angular = self.max_angular_setting
00430         try:
00431             set_max_speed_srv(req)
00432             self.max_speed_known = False
00433         except:
00434             pass
00435         
00436     def clear_max_speed(self):
00437         set_max_speed_srv = rospy.ServiceProxy('/mobility_base/set_max_speed', SetMaxSpeed)
00438         req = SetMaxSpeedRequest()
00439         req.linear = float('nan')
00440         req.angular = float('nan')
00441         try:
00442             set_max_speed_srv(req)
00443             self.max_speed_known = False
00444         except:
00445             pass
00446 
00447     def wake_days_changed(self):
00448         try:
00449             self.rel_wake_days = float(self._widget.wake_time_days_txt.text())
00450         except:
00451             self._widget.wake_time_days_txt.setText(str(self.rel_wake_days))
00452                         
00453     def wake_hours_changed(self):
00454         try:
00455             self.rel_wake_hours = float(self._widget.wake_time_hours_txt.text())
00456         except:
00457             self._widget.wake_time_hours_txt.setText(str(self.rel_wake_hours))
00458             
00459     def wake_minutes_changed(self):
00460         try:
00461             self.rel_wake_minutes = float(self._widget.wake_time_minutes_txt.text())
00462         except:
00463             self._widget.wake_time_minutes_txt.setText(str(self.rel_wake_minutes)) 
00464 
00465     def wake_secs_changed(self):
00466         try:
00467             self.rel_wake_secs = float(self._widget.wake_time_secs_txt.text())
00468         except:
00469             self._widget.wake_time_secs_txt.setText(str(self.rel_wake_secs)) 
00470 
00471     def set_relative_wake_time(self):
00472         new_wake_time = std_msgs.msg.Time()
00473         rel_wake_time = 86400 * self.rel_wake_days + 3600 * self.rel_wake_hours + 60 * self.rel_wake_minutes + self.rel_wake_secs
00474         new_wake_time.data = rospy.Time.now() + rospy.Duration(rel_wake_time)
00475         self.pub_set_wake_time.publish(new_wake_time)
00476         
00477     def set_absolute_wake_time(self):
00478         self.pub_set_wake_time.publish(rospy.Time(self._widget.absolute_wake_time_obj.dateTime().toTime_t()))
00479         
00480     def clear_wake_time(self):
00481         self.pub_set_wake_time.publish(rospy.Time(0))
00482     
00483     def refresh_max_speed(self):
00484         self.max_speed_dirty = True
00485         self.max_speed_known = False
00486     
00487     def update_gui_cb(self):
00488         
00489         # Switch between tabs and full GUI
00490         if self.is_currently_tab:
00491             if self._widget.height() > 830 and self._widget.width() > 1205:
00492                 self.is_currently_tab = False
00493                 self.context_.remove_widget(self._widget)
00494                 self.init_gui('full')
00495         else:
00496             if self._widget.height() < 810 or self._widget.width() < 1185:
00497                 self.is_currently_tab = True
00498                 self.context_.remove_widget(self._widget)
00499                 self.init_gui('tab')
00500         
00501         # Check connection to base
00502         if self.base_connected and (rospy.Time.now() - self.last_joystick_time).to_sec() > 1.0:
00503             self.base_connected = False
00504             self._widget.disconnected_lbl.setText('<font color=#FF0000>NOT CONNECTED</font>')
00505             self._widget.disconnected_lbl.setVisible(True)
00506         
00507         if not self.base_connected and (rospy.Time.now() - self.last_joystick_time).to_sec() < 1.0:
00508             self.base_connected = True
00509 #             self._widget.disconnected_lbl.setText('')
00510             self._widget.disconnected_lbl.setVisible(False)
00511         
00512         # Update checklists
00513         self.update_checklist();
00514 
00515         # Manage 5 second disable of gyro calibration button
00516         if not self.cal_enabled:
00517             if (rospy.Time.now() - self.cal_time).to_sec() > 5.0:
00518                 self._widget.gyro_cal_btn.setEnabled(True)
00519                 self._widget.gyro_cal_btn.setText('Calibrate')
00520                 self.cal_enabled = True
00521             else:
00522                 self._widget.gyro_cal_btn.setEnabled(False)
00523                 self._widget.gyro_cal_btn.setText(str(5 - 0.1*floor(10*(rospy.Time.now() - self.cal_time).to_sec()))) 
00524                 
00525         # Update joystick graphics
00526         if not self.check_joystick_valid():
00527             self.update_check_status(self._widget.joystick_bind_chk, self.NONE)
00528             
00529             if not self.joystick_bind_status:
00530                 self._widget.joystick_bind_lbl.setText('')
00531 
00532             
00533             for l in self.joystick_power_ind:
00534                 l.setVisible(True)
00535             self.update_right_stick_indicator(self.stick_ind_range_mid, self.stick_ind_range_mid)
00536             self.update_left_stick_indicator(self.stick_ind_range_mid, self.stick_ind_range_mid)
00537         else:
00538             self.update_check_status(self._widget.joystick_bind_chk, self.GOOD)
00539             self._widget.joystick_bind_lbl.setText('Joystick bound')
00540 
00541             for l in self.joystick_power_ind:
00542                 l.setVisible(False)
00543             self.update_right_stick_indicator(self.joystick_data[ChannelIndex.CHAN_LATERAL], self.joystick_data[ChannelIndex.CHAN_FORWARD])
00544             self.update_left_stick_indicator(self.joystick_data[ChannelIndex.CHAN_ROTATE], self.joystick_data[ChannelIndex.CHAN_ENABLE])
00545         if self.joystick_data[ChannelIndex.CHAN_MODE] < self.stick_ind_range_mid:
00546             self.mode_ind.setPen(self.cyan_pen)
00547             self._widget.modeLabel.setText("0 (Computer)")
00548         else:
00549             self.mode_ind.setPen(self.magenta_pen)
00550             self._widget.modeLabel.setText("1 (Manual)")
00551         
00552         # Update joystick data table
00553         for i in range(len(self.joystick_table_vals)):
00554             self.joystick_table_vals[i].setText(str(self.joystick_data[i]))
00555             
00556         # Update twist data table
00557         if self.command_received:
00558             self.twist_table_vals[0].setText(str(0.01 * floor(100 * self.current_cmd.linear.x)))
00559             self.twist_table_vals[1].setText(str(0.01 * floor(100 * self.current_cmd.linear.y)))
00560             self.twist_table_vals[2].setText(str(0.01 * floor(100 * self.current_cmd.angular.z)))
00561         else:
00562             self.twist_table_vals[0].setText('Not Published')
00563             self.twist_table_vals[1].setText('Not Published')
00564             self.twist_table_vals[2].setText('Not Published')
00565             
00566         # Update battery percentage
00567         self.battery_label.setText(str(self.battery_percent) + ' %')
00568         self.battery_voltage_label.setText(str(0.01 * floor(100 * self.battery_voltage)) + ' V')
00569         
00570         # Update mode
00571         self.mode_label.setText(self.get_mode_string(self.current_mode))
00572         
00573         # Update bumper graphics
00574         self.bumper_visible_switch(BumperIndex.BUMPER_1F, self.bumper_front_left)
00575         self.bumper_visible_switch(BumperIndex.BUMPER_2F, self.bumper_front_right)
00576         self.bumper_visible_switch(BumperIndex.BUMPER_3F, self.bumper_rear_left)
00577         self.bumper_visible_switch(BumperIndex.BUMPER_4F, self.bumper_rear_right)
00578         self.bumper_state_labels[0].setPlainText(str(self.bumper_front_left))
00579         self.bumper_state_labels[1].setPlainText(str(self.bumper_front_right))
00580         self.bumper_state_labels[2].setPlainText(str(self.bumper_rear_left))
00581         self.bumper_state_labels[3].setPlainText(str(self.bumper_rear_right))
00582         
00583         # Update gyro cal graphics
00584         if self.gyro_cal_status:            
00585             self.update_check_status(self._widget.gyro_cal_chk, self.GOOD)
00586             self._widget.gyro_cal_lbl.setText('Gyro calibrated')
00587         else:
00588             self.update_check_status(self._widget.gyro_cal_chk, self.BAD)
00589             self._widget.gyro_cal_lbl.setText('Gyro NOT calibrated')
00590     
00591         self._widget.gyro_x_lbl.setText('x: ' + str(1e-5*floor(1e5*self.gyro_x)))
00592         self._widget.gyro_y_lbl.setText('y: ' + str(1e-5*floor(1e5*self.gyro_y)))
00593         self._widget.gyro_z_lbl.setText('z: ' + str(1e-5*floor(1e5*self.gyro_z)))
00594     
00595         # Update max speed configuration
00596         if not self.max_speed_known:
00597             service_name = '/mobility_base/get_max_speed'
00598             get_max_speed_srv = rospy.ServiceProxy(service_name, GetMaxSpeed)
00599             
00600             try:
00601                 resp = get_max_speed_srv()
00602                 self.max_speed_known = True
00603                 self.max_linear_actual = resp.linear
00604                 self.max_angular_actual = resp.angular
00605                 
00606                 if self.max_linear_actual <= 0 or not isfinite(self.max_linear_actual):
00607                     self._widget.max_linear_lbl.setText('Unlimited')
00608                 else:
00609                     self._widget.max_linear_lbl.setText(str(1e-2*round(1e2*self.max_linear_actual)))
00610                 
00611                 if self.max_angular_actual <= 0 or not isfinite(self.max_angular_actual):
00612                     self._widget.max_angular_lbl.setText('Unlimited')
00613                 else:
00614                     self._widget.max_angular_lbl.setText(str(1e-2*round(1e2*self.max_angular_actual)))
00615 
00616             except:
00617                 pass
00618 #                 print service_name + " doesn't exist"
00619                 
00620         if self.max_speed_dirty:        
00621             self._widget.max_linear_txt.setText(str(self.max_linear_setting))
00622             self._widget.max_angular_txt.setText(str(self.max_angular_setting))
00623             self.max_speed_dirty = False
00624        
00625         # Wake time
00626         if self.current_wake_time == rospy.Time(0):
00627             self._widget.wake_time_lbl.setText('Not Set')
00628         else:
00629             self._widget.wake_time_lbl.setText(time.strftime('%m/%d/%Y,  %H:%M:%S', time.localtime(self.current_wake_time.to_sec())))
00630             
00631     def check_joystick_valid(self):
00632         return self.joystick_data[ChannelIndex.CHAN_FORWARD] > 0 or self.joystick_data[ChannelIndex.CHAN_LATERAL] > 0 or self.joystick_data[ChannelIndex.CHAN_ROTATE] > 0 or self.joystick_data[ChannelIndex.CHAN_MODE] > 0
00633             
00634     def get_mode_string(self, mode_num):
00635         if mode_num == Mode.MODE_ESTOP:
00636             return 'MODE_ESTOP'
00637         elif mode_num == Mode.MODE_DISABLED:
00638             return 'MODE_DISABLED'
00639         elif mode_num == Mode.MODE_BATTERY_LIMP_HOME:
00640             return 'MODE_BATTERY_LIMP_HOME'
00641         elif mode_num == Mode.MODE_BATTERY_CRITICAL:
00642             return 'MODE_BATTERY_CRITICAL'
00643         elif mode_num == Mode.MODE_WIRELESS:
00644             return 'MODE_WIRELESS'
00645         elif mode_num == Mode.MODE_TIMEOUT:
00646             return 'MODE_TIMEOUT'
00647         elif mode_num == Mode.MODE_VELOCITY:
00648             return 'MODE_VELOCITY'
00649         elif mode_num == Mode.MODE_VELOCITY_RAW:
00650             return 'MODE_VELOCITY_RAW'
00651         else:
00652             return ''
00653         
00654     def update_checklist(self):
00655         if self.current_mode >= Mode.MODE_TIMEOUT:
00656             self.checklist_status[self.BATT_MAN] = self.GOOD
00657             self.checklist_status[self.ESTOP_MAN] = self.GOOD
00658             self.checklist_status[self.DISABLE_MAN] = self.GOOD
00659             self.checklist_status[self.JOYSTICK_MAN] = self.BAD
00660             self.checklist_status[self.BATT_COMP] = self.GOOD
00661             self.checklist_status[self.ESTOP_COMP] = self.GOOD
00662             self.checklist_status[self.DISABLE_COMP] = self.GOOD
00663             self.checklist_status[self.JOYSTICK_COMP] = self.GOOD
00664         elif self.current_mode == Mode.MODE_WIRELESS:
00665             self.checklist_status[self.BATT_MAN] = self.GOOD
00666             self.checklist_status[self.ESTOP_MAN] = self.GOOD
00667             self.checklist_status[self.DISABLE_MAN] = self.GOOD
00668             self.checklist_status[self.JOYSTICK_MAN] = self.GOOD
00669             self.checklist_status[self.BATT_COMP] = self.GOOD
00670             self.checklist_status[self.ESTOP_COMP] = self.GOOD
00671             self.checklist_status[self.DISABLE_COMP] = self.GOOD
00672             self.checklist_status[self.JOYSTICK_COMP] = self.BAD
00673         elif self.current_mode == Mode.MODE_DISABLED:
00674             self.checklist_status[self.BATT_MAN] = self.NONE
00675             self.checklist_status[self.ESTOP_MAN] = self.GOOD
00676             self.checklist_status[self.DISABLE_MAN] = self.BAD
00677             self.checklist_status[self.JOYSTICK_MAN] = self.NONE
00678             self.checklist_status[self.BATT_COMP] = self.NONE
00679             self.checklist_status[self.ESTOP_COMP] = self.GOOD
00680             self.checklist_status[self.DISABLE_COMP] = self.BAD
00681             self.checklist_status[self.JOYSTICK_COMP] = self.NONE
00682         elif self.current_mode == Mode.MODE_ESTOP:
00683             self.checklist_status[self.BATT_MAN] = self.NONE
00684             self.checklist_status[self.ESTOP_MAN] = self.BAD
00685             self.checklist_status[self.DISABLE_MAN] = self.NONE
00686             self.checklist_status[self.JOYSTICK_MAN] = self.NONE
00687             self.checklist_status[self.BATT_COMP] = self.NONE
00688             self.checklist_status[self.ESTOP_COMP] = self.BAD
00689             self.checklist_status[self.DISABLE_COMP] = self.NONE
00690             self.checklist_status[self.JOYSTICK_COMP] = self.NONE
00691         elif self.current_mode == Mode.MODE_BATTERY_CRITICAL:
00692             self.checklist_status[self.BATT_MAN] = self.BAD
00693             self.checklist_status[self.ESTOP_MAN] = self.GOOD
00694             self.checklist_status[self.DISABLE_MAN] = self.GOOD
00695             self.checklist_status[self.JOYSTICK_MAN] = self.NONE
00696             self.checklist_status[self.BATT_COMP] = self.BAD
00697             self.checklist_status[self.ESTOP_COMP] = self.GOOD
00698             self.checklist_status[self.DISABLE_COMP] = self.GOOD
00699             self.checklist_status[self.JOYSTICK_COMP] = self.NONE
00700         elif self.current_mode == Mode.MODE_BATTERY_LIMP_HOME:
00701             self.checklist_status[self.BATT_MAN] = self.GOOD
00702             self.checklist_status[self.ESTOP_MAN] = self.GOOD
00703             self.checklist_status[self.DISABLE_MAN] = self.GOOD
00704             self.checklist_status[self.JOYSTICK_MAN] = self.NONE
00705             self.checklist_status[self.BATT_COMP] = self.BAD
00706             self.checklist_status[self.ESTOP_COMP] = self.GOOD
00707             self.checklist_status[self.DISABLE_COMP] = self.GOOD
00708             self.checklist_status[self.JOYSTICK_COMP] = self.NONE
00709         
00710         # Check if joystick is suppressed by topic
00711         if self.joystick_suppressed:
00712             self.checklist_status[self.SUPPRESS_COMP] = self.GOOD
00713             self.checklist_status[self.DISABLE_COMP] = self.NONE
00714             self.checklist_status[self.JOYSTICK_COMP] = self.NONE
00715         else:
00716             self.checklist_status[self.SUPPRESS_COMP] = self.NONE
00717         if (rospy.Time.now() - self.last_suppress_time).to_sec() > self.JOYSTICK_SUPPRESS_PERIOD:
00718             self.checklist_status[self.SUPPRESS_MAN] = self.GOOD
00719         else:
00720             self.checklist_status[self.SUPPRESS_MAN] = self.BAD
00721         
00722         # Command message received
00723         if self.command_received:
00724             self.checklist_status[self.CMD_COMP] = self.GOOD
00725         else:
00726             self.checklist_status[self.CMD_COMP] = self.BAD
00727             
00728         # Override twist checkbox if mode is in TIMEOUT
00729         if self.current_mode == Mode.MODE_TIMEOUT:
00730             self.checklist_status[self.CMD_COMP] = self.BAD
00731         
00732         # Update checklist graphics    
00733         self.update_check_status(self._widget.batt_man_chk, self.checklist_status[self.BATT_MAN])
00734         self.update_check_status(self._widget.estop_man_chk, self.checklist_status[self.ESTOP_MAN])
00735         self.update_check_status(self._widget.disable_man_chk, self.checklist_status[self.DISABLE_MAN])
00736         self.update_check_status(self._widget.joystick_man_chk, self.checklist_status[self.JOYSTICK_MAN])
00737         self.update_check_status(self._widget.suppress_man_chk, self.checklist_status[self.SUPPRESS_MAN])
00738         self.update_check_status(self._widget.batt_comp_chk, self.checklist_status[self.BATT_COMP])
00739         self.update_check_status(self._widget.estop_comp_chk, self.checklist_status[self.ESTOP_COMP])
00740         self.update_check_status(self._widget.disable_comp_chk, self.checklist_status[self.DISABLE_COMP])
00741         self.update_check_status(self._widget.joystick_comp_chk, self.checklist_status[self.JOYSTICK_COMP])
00742         self.update_check_status(self._widget.suppress_comp_chk, self.checklist_status[self.SUPPRESS_COMP])
00743         self.update_check_status(self._widget.cmd_comp_chk, self.checklist_status[self.CMD_COMP])
00744         self.update_check_status(self._widget.joystick_bind_chk, self.NONE)
00745 
00746     def update_check_status(self, obj, icon_type):
00747         if icon_type == self.GOOD:
00748             obj.setPixmap(self.good_icon)
00749         elif icon_type == self.BAD:
00750             obj.setPixmap(self.bad_icon)
00751         else:
00752             obj.setPixmap(self.none_icon)
00753         
00754     def update_table(self):
00755         for i in range(0, len(self.joystick_table_vals)):
00756             self.joystick_table_vals[i].setText(55)
00757     
00758     def recv_mode(self, mode_msg):
00759         self.current_mode = mode_msg.mode
00760     
00761     def recv_suppress(self, suppress_msg):
00762         self.suppress_dt = rospy.Time.now() - self.last_suppress_time
00763         self.last_suppress_time = rospy.Time.now()
00764     
00765     def recv_twist(self, twist_msg):
00766         self.twist_dt = rospy.Time.now() - self.last_twist_time
00767         self.last_twist_time = rospy.Time.now()
00768         self.current_cmd = twist_msg
00769     
00770     def recv_joystick(self, joystick_msg):
00771         self.joystick_data = joystick_msg.channels;
00772         self.last_joystick_time = rospy.Time.now()
00773     
00774     def recv_bumpers(self, bumper_msg):
00775         self.bumper_front_left = bumper_msg.front_left
00776         self.bumper_front_right = bumper_msg.front_right
00777         self.bumper_rear_left = bumper_msg.rear_left
00778         self.bumper_rear_right = bumper_msg.rear_right
00779     
00780     def recv_battery(self, battery_msg):
00781         self.battery_percent = battery_msg.percent
00782         self.battery_voltage = battery_msg.voltage
00783     
00784     def recv_bind_status(self, bind_msg):
00785         self.joystick_bind_status = bind_msg.data
00786         
00787         if bind_msg.data:
00788             if self.joystick_bind_dot_counter == 0:
00789                 self._widget.joystick_bind_lbl.setText('Binding.')
00790             elif self.joystick_bind_dot_counter == 1:
00791                 self._widget.joystick_bind_lbl.setText('Binding..')
00792             elif self.joystick_bind_dot_counter == 2:
00793                 self._widget.joystick_bind_lbl.setText('Binding...')
00794                 
00795             self.joystick_bind_dot_counter = (self.joystick_bind_dot_counter + 1) % 3
00796 
00797     def recv_gyro_calibrated(self, cal_msg):
00798         self.gyro_cal_status = cal_msg.data
00799             
00800     def recv_imu(self, imu_msg):
00801         self.gyro_x = imu_msg.angular_velocity.x
00802         self.gyro_y = imu_msg.angular_velocity.y
00803         self.gyro_z = imu_msg.angular_velocity.z
00804     
00805     def recv_wake_time(self, time_msg):
00806         self.current_wake_time = time_msg.data
00807             
00808     def subscribe_topics(self):
00809         sub_joystick = rospy.Subscriber('/mobility_base/joystick_raw', JoystickRaw, self.recv_joystick)
00810         sub_suppress = rospy.Subscriber('/mobility_base/suppress_wireless', std_msgs.msg.Empty, self.recv_suppress)
00811         sub_twist = rospy.Subscriber('/mobility_base/cmd_vel', Twist, self.recv_twist)
00812         sub_mode = rospy.Subscriber('/mobility_base/mode', Mode, self.recv_mode)
00813         sub_bumpers = rospy.Subscriber('/mobility_base/bumper_states', BumperState, self.recv_bumpers)
00814         sub_battery = rospy.Subscriber('/mobility_base/battery', BatteryState, self.recv_battery)
00815         sub_bind = rospy.Subscriber('/mobility_base/bind_status', std_msgs.msg.Bool, self.recv_bind_status)
00816         sub_gyro_calibrated = rospy.Subscriber('/mobility_base/imu/is_calibrated', std_msgs.msg.Bool, self.recv_gyro_calibrated)
00817         sub_imu = rospy.Subscriber('/mobility_base/imu/data_raw', Imu, self.recv_imu)
00818         sub_wake_time = rospy.Subscriber('/mobility_base/wake_time', std_msgs.msg.Time, self.recv_wake_time)
00819     
00820     def advertise_topics(self):
00821         self.pub_start_bind = rospy.Publisher('/mobility_base/bind_start', std_msgs.msg.Empty, queue_size=1)
00822         self.pub_stop_bind = rospy.Publisher('/mobility_base/bind_stop', std_msgs.msg.Empty, queue_size=1)
00823         self.pub_set_wake_time = rospy.Publisher('/mobility_base/set_wake_time', std_msgs.msg.Time, queue_size=1)
00824     
00825     def init_joystick_graphics(self):
00826         # Pens
00827         self.cyan_pen = QPen(QColor(0, 255, 255))
00828         self.magenta_pen = QPen(QColor(255, 0, 255))
00829         self.red_pen = QPen(QColor(255, 0, 0))
00830         self.cyan_pen.setWidth(3)
00831         self.magenta_pen.setWidth(3)
00832         self.red_pen.setWidth(3)
00833         self.stick_ind_l = QGraphicsEllipseItem()
00834         self.stick_ind_r = QGraphicsEllipseItem()
00835         self.stick_line_l = QGraphicsLineItem()
00836         self.stick_line_r = QGraphicsLineItem()
00837         self.mode_ind = QGraphicsLineItem()
00838         
00839         # Left joystick indicator circle
00840         px_l = self.stick_ind_lox - self.stick_ind_radius
00841         py_l = self.stick_ind_loy - self.stick_ind_radius
00842         self.stick_ind_l.setRect(px_l, py_l, 2 * self.stick_ind_radius, 2 * self.stick_ind_radius)
00843         self.stick_ind_l.setBrush(QBrush(QColor(255, 0, 0)))
00844         self.stick_ind_l.setPen(QPen(QColor(0, 0, 0)))  
00845         
00846         # Right joystick indicator circle
00847         px_r = self.stick_ind_rox - self.stick_ind_radius
00848         py_r = self.stick_ind_roy - self.stick_ind_radius
00849         self.stick_ind_r.setRect(px_r, py_r, 2 * self.stick_ind_radius, 2 * self.stick_ind_radius)
00850         self.stick_ind_r.setBrush(QBrush(QColor(255, 0, 0)))
00851         self.stick_ind_r.setPen(QPen(QColor(0, 0, 0)))
00852         
00853         # Left joystick indicator line
00854         line_pen = QPen(QColor(255,0,0))
00855         line_pen.setWidth(4)
00856         self.stick_line_l.setLine(self.stick_ind_lox, self.stick_ind_loy, self.stick_ind_lox, self.stick_ind_loy)
00857         self.stick_line_l.setPen(line_pen)
00858         
00859         # Right joystick indicator line
00860         self.stick_line_r.setLine(self.stick_ind_rox, self.stick_ind_roy, self.stick_ind_rox, self.stick_ind_roy)
00861         self.stick_line_r.setPen(line_pen) 
00862         
00863         # Mode indicator line
00864         self.mode_ind.setLine(self.mode_ind_x1, self.mode_ind_y1, self.mode_ind_x2, self.mode_ind_y2)
00865         self.mode_ind.setPen(self.cyan_pen)
00866         
00867         # Joystick power indicator
00868         self.joystick_power_ind = []
00869         self.joystick_power_ind.append(QGraphicsLineItem(self.power_ind_x1, self.power_ind_y + 20, self.power_ind_x1, self.power_ind_y - 20))
00870         self.joystick_power_ind.append(QGraphicsLineItem(self.power_ind_x1, self.power_ind_y - 20, self.power_ind_x1 + 50, self.power_ind_y - 20))
00871         self.joystick_power_ind.append(QGraphicsLineItem(self.power_ind_x1+50, self.power_ind_y - 20, self.power_ind_x1+50, self.power_ind_y + 20))
00872         self.joystick_power_ind.append(QGraphicsLineItem(self.power_ind_x1+50, self.power_ind_y + 20, self.power_ind_x1, self.power_ind_y + 20))
00873         
00874         # Populate scene
00875         graphics_scene = QGraphicsScene()
00876         graphics_scene.addItem(self.stick_ind_l)
00877         graphics_scene.addItem(self.stick_ind_r)
00878         graphics_scene.addItem(self.stick_line_l)
00879         graphics_scene.addItem(self.stick_line_r)
00880         graphics_scene.addItem(self.mode_ind)
00881         for l in self.joystick_power_ind:
00882             l.setPen(self.red_pen)
00883             graphics_scene.addItem(l)
00884         graphics_scene.setSceneRect(0, 0, self._widget.joystickGraphicsView.width() - 4, self._widget.joystickGraphicsView.height() - 4)
00885         self._widget.joystickGraphicsView.setScene(graphics_scene)
00886         self._widget.joystickGraphicsView.setBackgroundBrush(QBrush(QImage(os.path.join(rospkg.RosPack().get_path('mobility_base_tools'), 'images', 'dx6ilabels.jpg'))))
00887         self._widget.joystickGraphicsView.show()
00888         
00889     def init_bumper_graphics(self):
00890         
00891         # Pens
00892         self.blue_pen = QPen(QColor(0,0,255))
00893         self.blue_pen.setWidth(10)
00894         
00895         self.bumper_lines = []
00896 
00897         # Text state labels
00898         self.bumper_state_labels = [QGraphicsTextItem() for i in range(0,4)]
00899         for i in range(len(self.bumper_state_labels)):
00900             self.bumper_state_labels[i].setFont(QFont('Ubuntu', 14, QFont.Bold))
00901             self.bumper_state_labels[i].setPlainText('00')
00902         self.bumper_state_labels[0].setPos(self.bumper_fl_x-10, self.bumper_fl_y + 55)
00903         self.bumper_state_labels[1].setPos(self.bumper_fr_x-10, self.bumper_fr_y + 55)
00904         self.bumper_state_labels[2].setPos(self.bumper_rl_x-10, self.bumper_rl_y - 80)
00905         self.bumper_state_labels[3].setPos(self.bumper_rr_x-10, self.bumper_rr_y - 80)
00906         
00907         # Bumper indicator lines
00908         self.bumper_line(self.bumper_fl_x - 20, self.bumper_fl_y - self.bumper_dy, True)
00909         self.bumper_line(self.bumper_fl_x - self.bumper_dx, self.bumper_fl_y - 20, False)
00910         self.bumper_line(self.bumper_fl_x + self.bumper_dx, self.bumper_fl_y - 20, False)
00911         self.bumper_line(self.bumper_fl_x - 20, self.bumper_fl_y + self.bumper_dy, True)
00912         self.bumper_line(self.bumper_fr_x - 20, self.bumper_fr_y - self.bumper_dy, True)
00913         self.bumper_line(self.bumper_fr_x - self.bumper_dx, self.bumper_fr_y - 20, False)
00914         self.bumper_line(self.bumper_fr_x + self.bumper_dx, self.bumper_fr_y - 20, False)
00915         self.bumper_line(self.bumper_fr_x - 20, self.bumper_fr_y + self.bumper_dy, True)
00916         self.bumper_line(self.bumper_rl_x - 20, self.bumper_rl_y - self.bumper_dy, True)
00917         self.bumper_line(self.bumper_rl_x - self.bumper_dx, self.bumper_rl_y - 20, False)
00918         self.bumper_line(self.bumper_rl_x + self.bumper_dx, self.bumper_rl_y - 20, False)
00919         self.bumper_line(self.bumper_rl_x - 20, self.bumper_rl_y + self.bumper_dy, True)
00920         self.bumper_line(self.bumper_rr_x - 20, self.bumper_rr_y - self.bumper_dy, True)
00921         self.bumper_line(self.bumper_rr_x - self.bumper_dx, self.bumper_rr_y - 20, False)
00922         self.bumper_line(self.bumper_rr_x + self.bumper_dx, self.bumper_rr_y - 20, False)
00923         self.bumper_line(self.bumper_rr_x - 20, self.bumper_rr_y + self.bumper_dy, True)
00924         
00925         # Populate scene
00926         graphics_scene = QGraphicsScene()
00927         for bumper in self.bumper_lines:
00928             graphics_scene.addItem(bumper)
00929         for label in self.bumper_state_labels:
00930             graphics_scene.addItem(label)
00931         graphics_scene.setSceneRect(0, 0, self._widget.bumperGraphicsView.width() - 4, self._widget.bumperGraphicsView.height() - 4)
00932         self._widget.bumperGraphicsView.setScene(graphics_scene)
00933         self._widget.bumperGraphicsView.setBackgroundBrush(QBrush(QImage(os.path.join(rospkg.RosPack().get_path('mobility_base_tools'), 'images', 'mb_top.png'))))
00934         self._widget.bumperGraphicsView.show()
00935     
00936     def bumper_line(self, x, y, front):
00937         new_line = QGraphicsLineItem()
00938         if front:
00939             new_line.setLine(x, y, x+40, y)
00940         else:
00941             new_line.setLine(x, y, x, y+40)
00942         new_line.setPen(self.blue_pen)
00943         new_line.setVisible(False)
00944         self.bumper_lines.append(new_line)
00945         
00946     def bumper_visible_switch(self, idx, bumper_state):
00947         if bumper_state & BumperState.BUMPER_FRONT:
00948             self.bumper_lines[idx].setVisible(True)
00949         else:
00950             self.bumper_lines[idx].setVisible(False)
00951         if bumper_state & BumperState.BUMPER_LEFT:
00952             self.bumper_lines[idx+1].setVisible(True)
00953         else:
00954             self.bumper_lines[idx+1].setVisible(False)
00955         if bumper_state & BumperState.BUMPER_RIGHT:
00956             self.bumper_lines[idx+2].setVisible(True)
00957         else:
00958             self.bumper_lines[idx+2].setVisible(False)  
00959         if bumper_state & BumperState.BUMPER_REAR:
00960             self.bumper_lines[idx+3].setVisible(True)
00961         else:
00962             self.bumper_lines[idx+3].setVisible(False)
00963 
00964     def reset_gui_timer(self):
00965         self.gui_update_timer = QTimer(self._widget)
00966         self.gui_update_timer.setInterval(100)
00967         self.gui_update_timer.setSingleShot(False)
00968         self.gui_update_timer.timeout.connect(lambda: self.update_gui_cb())
00969         self.gui_update_timer.start()
00970         
00971     def spawn_full_gui(self):
00972         super(DiagnosticGui, self).__init__(self.context_)
00973         # Give QObjects reasonable names
00974         self.setObjectName('DiagnosticGui')
00975 
00976         # Create QWidget
00977         self._widget = QWidget()
00978 
00979         # Get path to UI file which should be in the "resource" folder of this package
00980         ui_file = os.path.join(rospkg.RosPack().get_path('mobility_base_tools'), 'resource', 'DiagnosticGui.ui')
00981         # Extend the widget with all attributes and children from UI file
00982         loadUi(ui_file, self._widget)
00983         # Give QObjects reasonable names
00984         self._widget.setObjectName('DiagnosticGui' + str(self.widget_count))
00985         self.widget_count += 1
00986         # Add widget to the user interface
00987         self.context_.add_widget(self._widget)
00988         
00989     def spawn_tab_gui(self):
00990         super(DiagnosticGui, self).__init__(self.context_)
00991         # Give QObjects reasonable names
00992         self.setObjectName('DiagnosticGui')
00993 
00994         # Create QWidget
00995         self._widget = QWidget()
00996         
00997         # Get path to UI file which should be in the "resource" folder of this package
00998         ui_file = os.path.join(rospkg.RosPack().get_path('mobility_base_tools'), 'resource', 'DiagnosticGuiTabs.ui')
00999         # Extend the widget with all attributes and children from UI file
01000         loadUi(ui_file, self._widget)
01001         # Give QObjects reasonable names
01002         self._widget.setObjectName('DiagnosticGui' + str(self.widget_count))
01003         self.widget_count += 1
01004         # Add widget to the user interface
01005         self.context_.add_widget(self._widget)
01006         
01007     def update_right_stick_indicator(self, lat_val, forward_val):
01008         horiz_val = -self.stick_ind_range_factor * (lat_val - self.stick_ind_range_mid)
01009         vert_val = -self.stick_ind_range_factor * (forward_val - self.stick_ind_range_mid)
01010         r = sqrt(horiz_val * horiz_val + vert_val * vert_val)
01011         if r > self.stick_ind_range_pix / 2:
01012             r = self.stick_ind_range_pix / 2
01013         ang = atan2(vert_val, horiz_val)    
01014         px = r * cos(ang)
01015         py = r * sin(ang)
01016         self.stick_ind_r.setPos(QPoint(px, py))
01017         self.stick_line_r.setLine(self.stick_ind_rox, self.stick_ind_roy, self.stick_ind_rox + px, self.stick_ind_roy + py)
01018     
01019     def update_left_stick_indicator(self, yaw_val, enable_val):
01020         horiz_val = -self.stick_ind_range_factor * (yaw_val - self.stick_ind_range_mid)
01021         vert_val = -self.stick_ind_range_factor * (enable_val - self.stick_ind_range_mid)
01022         r = sqrt(horiz_val * horiz_val + vert_val * vert_val)
01023         if r > self.stick_ind_range_pix / 2:
01024             r = self.stick_ind_range_pix / 2
01025         ang = atan2(vert_val, horiz_val)    
01026         px = r * cos(ang)
01027         py = r * sin(ang)
01028         self.stick_ind_l.setPos(QPoint(px, py))
01029         self.stick_line_l.setLine(self.stick_ind_lox, self.stick_ind_loy, self.stick_ind_lox + px, self.stick_ind_loy + py)        
01030     
01031     def shutdown_plugin(self):
01032         pass


mobility_base_tools
Author(s): Dataspeed Inc.
autogenerated on Thu Jun 6 2019 21:45:37