class DiagnosticGui(Plugin): last_suppress_time = Time() last_twist_time = Time() gui_update_timer = QTimer() # Raw joystick data joystick_data = [] joystick_table_vals = [] joystick_channel_text = ['CHAN_ENABLE: ', 'CHAN_ROTATE: ', 'CHAN_FORWARD: ', 'CHAN_LATERAL: ', 'CHAN_MODE: ', 'CHAN_EXTRA: '] joystick_bind_status = False joystick_bind_dot_counter = 0 # Mode current_mode = -1 # Topic pub timeouts JOYSTICK_SUPPRESS_PERIOD = 0.2 # 5 Hz CMD_VEL_TIMEOUT_PERIOD = 0.2 # 5 Hz joystick_suppressed = False command_received = False current_cmd = Twist() battery_percent = 0 battery_voltage = 0 # Checklist icons bad_icon = QPixmap() good_icon = QPixmap() none_icon = QPixmap() # Checklist status GOOD = 0 BAD = 1 NONE = 2 # Checklist variables checklist_status = [] BATT_MAN = 0 ESTOP_MAN = 1 DISABLE_MAN = 2 JOYSTICK_MAN = 3 SUPPRESS_MAN = 4 BATT_COMP = 5 ESTOP_COMP = 6 DISABLE_COMP = 7 JOYSTICK_COMP = 8 SUPPRESS_COMP = 9 CMD_COMP = 10 # Bumpers bumper_front_left = 0 bumper_front_right = 0 bumper_rear_left = 0 bumper_rear_right = 0 # Gyro cal gyro_cal_status = False gyro_x = 0.0 gyro_y = 0.0 gyro_z = 0.0 cal_enabled = True cal_time = rospy.Time(0) # Max speed config max_speed_known = False max_speed_dirty = True max_linear_actual = 0.0 max_angular_actual = 0.0 max_linear_setting = 0.0 max_angular_setting = 0.0 # Wake time current_wake_time = rospy.Time(0) rel_wake_days = 0 rel_wake_hours = 0 rel_wake_minutes = 0 rel_wake_secs = 0 # Switching between tabs and full GUI is_currently_tab = False widget_count = 0 current_tab_idx = -1 raw_data_tab_idx = 5 # Check connection to base base_connected = False last_joystick_time = rospy.Time(0) # Constants stick_ind_lox = 80 stick_ind_loy = 136 stick_ind_rox = 286 stick_ind_roy = 135 stick_ind_range_pix = 88.0 stick_ind_range_max = JoystickRaw.MAX stick_ind_range_min = JoystickRaw.MIN stick_ind_range_mid = JoystickRaw.CENTER stick_ind_range_factor = stick_ind_range_pix / (stick_ind_range_max - stick_ind_range_min) stick_ind_radius = 7 mode_ind_x1 = 52 mode_ind_y1 = 37 mode_ind_x2 = 44 mode_ind_y2 = 13 power_ind_x1 = 160 power_ind_x2 = 206 power_ind_y = 213 bumper_fl_x = 70 bumper_fl_y = 60 bumper_fr_x = 293 bumper_fr_y = 60 bumper_rl_x = 70 bumper_rl_y = 282 bumper_rr_x = 293 bumper_rr_y = 282 bumper_dx = 62 bumper_dy = 54 joystick_table_left_edge = 440 joystick_table_top_edge = 525 twist_table_left_edge = 700 twist_table_top_edge = 580 battery_table_left_edge = 700 battery_table_top_edge = 730 def __init__(self, context): # Qt setup self.context_ = context self.initGui('full') # ROS setup topic_timeout_timer = rospy.Timer(rospy.Duration(0.02), self.topicTimeoutCallback) self.subscribeTopics() self.advertiseTopics() def initGui(self, gui_type): if gui_type == 'full': self.spawnFullGui() self.initTables(self._widget, self.joystick_table_left_edge, self.joystick_table_top_edge) else: self.spawnTabGui() self.initTables(self._widget.gui_tabs.widget(self.raw_data_tab_idx), 20, 20) self._widget.gui_tabs.setCurrentIndex(self.current_tab_idx) self.resetGuiTimer() self.initJoystickGraphics() self.initBumperGraphics() self.initChecklists() self.bindCallbacks() self.refreshMaxSpeed() # Initialize absolute wake time setter to current time datetime_now = QDateTime(QDate.currentDate(), QTime.currentTime()) self._widget.absolute_wake_time_obj.setDateTime(datetime_now) temp_time = self._widget.absolute_wake_time_obj.time() temp_time = QTime(temp_time.hour(), temp_time.minute()) self._widget.absolute_wake_time_obj.setTime(temp_time) # Set connection label text if self.base_connected: self._widget.disconnected_lbl.setVisible(False) else: self._widget.disconnected_lbl.setVisible(True) self._widget.disconnected_lbl.setText('<font color=#FF0000>NOT CONNECTED</font>') def topicTimeoutCallback(self, event): # Joystick suppression if (event.current_real - self.last_suppress_time).to_sec() < self.JOYSTICK_SUPPRESS_PERIOD and self.suppress_dt.to_sec() <= 1.0/9.0: self.joystick_suppressed = True else: self.joystick_suppressed = False # Command message 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: self.command_received = True else: self.command_received = False def initChecklists(self): self.bad_icon.load(os.path.join(rospkg.RosPack().get_path('mobility_base_tools'), 'images', 'bad.png')) self.good_icon.load(os.path.join(rospkg.RosPack().get_path('mobility_base_tools'), 'images', 'good.png')) self.none_icon.load(os.path.join(rospkg.RosPack().get_path('mobility_base_tools'), 'images', 'none.png')) self.checklist_status=[0 for i in range(self.CMD_COMP + 1)] self.checklist_status[self.BATT_MAN] = self.NONE self.checklist_status[self.ESTOP_MAN] = self.NONE self.checklist_status[self.DISABLE_MAN] = self.NONE self.checklist_status[self.JOYSTICK_MAN] = self.NONE self.checklist_status[self.SUPPRESS_MAN] = self.NONE self.checklist_status[self.BATT_COMP] = self.NONE self.checklist_status[self.ESTOP_COMP] = self.NONE self.checklist_status[self.DISABLE_COMP] = self.NONE self.checklist_status[self.JOYSTICK_COMP] = self.NONE self.checklist_status[self.SUPPRESS_COMP] = self.NONE self.checklist_status[self.CMD_COMP] = self.NONE def initTabTables(self): self.joystick_table_vals = [QLabel(self._widget.gui_tabs.widget(self.raw_data_tab_idx)) for i in range(ChannelIndex.CHAN_EXTRA+1)] self.joystick_table_labels = [QLabel(self._widget.gui_tabs.widget(self.raw_data_tab_idx)) for i in range(ChannelIndex.CHAN_EXTRA+1)] self.joystick_table_heading = QLabel(self._widget.gui_tabs.widget(self.raw_data_tab_idx)) def initTables(self, widget, left, top): # Joystick data table self.joystick_data = [0 for i in range(ChannelIndex.CHAN_EXTRA+1)] self.joystick_table_vals = [QLabel(widget) for i in range(ChannelIndex.CHAN_EXTRA+1)] self.joystick_table_labels = [QLabel(widget) for i in range(ChannelIndex.CHAN_EXTRA+1)] self.joystick_table_heading = QLabel(widget) self.joystick_table_heading.setText('Raw Joystick Data') self.joystick_table_heading.setFont(QFont('Ubuntu', 11, QFont.Bold)) self.joystick_table_heading.move(left, top) for i in range(len(self.joystick_table_vals)): self.joystick_table_vals[i].move(left + 150, top + 30 * (i+1)) self.joystick_table_vals[i].setText('0000') self.joystick_table_vals[i].setFixedWidth(200) self.joystick_table_labels[i].move(left, top + 30 * (i+1)) self.joystick_table_labels[i].setText(self.joystick_channel_text[i]) # Twist data table self.twist_table_heading = QLabel(widget) self.twist_table_heading.setText('Current Twist Command') self.twist_table_heading.setFont(QFont('Ubuntu', 11, QFont.Bold)) self.twist_table_heading.move(left + 260, top) self.twist_table_labels = [QLabel(widget) for i in range(0, 3)] self.twist_table_vals = [QLabel(widget) for i in range(0, 3)] for i in range(len(self.twist_table_vals)): self.twist_table_vals[i].move(left + 260 + 150, top + 30 * (i+1)) self.twist_table_vals[i].setText('Not Published') self.twist_table_vals[i].setFixedWidth(200) self.twist_table_labels[i].move(left + 260, top + 30 * (i+1)) self.twist_table_labels[0].setText('Forward (m/s):') self.twist_table_labels[1].setText('Lateral (m/s):') self.twist_table_labels[2].setText('Rotation (rad/s):') # Battery percentage self.battery_heading = QLabel(widget) self.battery_heading.setText('Current Battery State') self.battery_heading.setFont(QFont('Ubuntu', 11, QFont.Bold)) self.battery_heading.move(left + 260, top + 150) self.battery_label = QLabel(widget) self.battery_label.move(left + 260, top + 150 +30) self.battery_label.setText('000 %') self.battery_voltage_label = QLabel(widget) self.battery_voltage_label.move(left + 260, top + 150 +60) self.battery_voltage_label.setText('00.00 V') self.battery_voltage_label.setFixedWidth(200) # Mode self.mode_heading = QLabel(widget) self.mode_heading.setFont(QFont('Ubuntu', 11, QFont.Bold)) self.mode_heading.move(left, top + 225) self.mode_heading.setText('Current Mode') self.mode_label = QLabel(widget) self.mode_label.move(left + 120, top + 225) self.mode_label.setText('XXXXXXXXXXXXXXXXXXXXXX') def bindCallbacks(self): self._widget.start_bind_btn.clicked.connect(self.startBind) self._widget.stop_bind_btn.clicked.connect(self.stopBind) self._widget.gyro_cal_btn.clicked.connect(self.calGyro) self._widget.clear_cal_btn.clicked.connect(self.clearCal) self._widget.max_linear_txt.editingFinished.connect(self.maxLinearChanged) self._widget.max_angular_txt.editingFinished.connect(self.maxAngularChanged) self._widget.set_speed_btn.clicked.connect(self.setMaxSpeed) self._widget.clear_speed_btn.clicked.connect(self.clearMaxSpeed) self._widget.wake_time_days_txt.editingFinished.connect(self.wakeDaysChanged) self._widget.wake_time_hours_txt.editingFinished.connect(self.wakeHoursChanged) self._widget.wake_time_minutes_txt.editingFinished.connect(self.wakeMinutesChanged) self._widget.wake_time_secs_txt.editingFinished.connect(self.wakeSecsChanged) self._widget.set_relative_wake_time_btn.clicked.connect(self.setRelativeWakeTime) self._widget.set_absolute_wake_time_btn.clicked.connect(self.setAbsoluteWakeTime) self._widget.clear_wake_time_btn.clicked.connect(self.clearWakeTime) if self.is_currently_tab: self._widget.gui_tabs.currentChanged.connect(self.setCurrentTab) def setCurrentTab(self, idx): self.current_tab_idx = self._widget.gui_tabs.currentIndex() def startBind(self): self.pub_start_bind.publish(std_msgs.msg.Empty()) def stopBind(self): self.pub_stop_bind.publish(std_msgs.msg.Empty()) def calGyro(self): gyro_cal_srv = rospy.ServiceProxy('/mobility_base/imu/calibrate', std_srvs.srv.Empty) try: gyro_cal_srv() self.cal_enabled = False self.cal_time = rospy.Time.now() except: pass def clearCal(self): clear_cal_srv = rospy.ServiceProxy('/mobility_base/imu/clear_cal', std_srvs.srv.Empty) try: clear_cal_srv() except: pass def maxLinearChanged(self): try: float_val = float(self._widget.max_linear_txt.text()) self.max_linear_setting = float_val; except ValueError: if self.max_linear_actual <= 0 or not isfinite(self.max_linear_actual): self.max_linear_setting = 0.0 else: self.max_linear_setting = self.max_linear_actual self.max_speed_dirty = True def maxAngularChanged(self): try: float_val = float(self._widget.max_angular_txt.text()) self.max_angular_setting = float_val; except ValueError: if self.max_angular_actual <= 0 or not isfinite(self.max_angular_actual): self.max_angular_setting = 0.0 else: self.max_angular_setting = self.max_angular_actual self.max_speed_dirty = True def setMaxSpeed(self): set_max_speed_srv = rospy.ServiceProxy('/mobility_base/set_max_speed', SetMaxSpeed) req = SetMaxSpeedRequest() req.linear = self.max_linear_setting req.angular = self.max_angular_setting try: set_max_speed_srv(req) self.max_speed_known = False except: pass def clearMaxSpeed(self): set_max_speed_srv = rospy.ServiceProxy('/mobility_base/set_max_speed', SetMaxSpeed) req = SetMaxSpeedRequest() req.linear = float('nan') req.angular = float('nan') try: set_max_speed_srv(req) self.max_speed_known = False except: pass def wakeDaysChanged(self): try: self.rel_wake_days = float(self._widget.wake_time_days_txt.text()) except: self._widget.wake_time_days_txt.setText(str(self.rel_wake_days)) def wakeHoursChanged(self): try: self.rel_wake_hours = float(self._widget.wake_time_hours_txt.text()) except: self._widget.wake_time_hours_txt.setText(str(self.rel_wake_hours)) def wakeMinutesChanged(self): try: self.rel_wake_minutes = float(self._widget.wake_time_minutes_txt.text()) except: self._widget.wake_time_minutes_txt.setText(str(self.rel_wake_minutes)) def wakeSecsChanged(self): try: self.rel_wake_secs = float(self._widget.wake_time_secs_txt.text()) except: self._widget.wake_time_secs_txt.setText(str(self.rel_wake_secs)) def setRelativeWakeTime(self): new_wake_time = std_msgs.msg.Time() rel_wake_time = 86400 * self.rel_wake_days + 3600 * self.rel_wake_hours + 60 * self.rel_wake_minutes + self.rel_wake_secs new_wake_time.data = rospy.Time.now() + rospy.Duration(rel_wake_time) self.pub_set_wake_time.publish(new_wake_time) def setAbsoluteWakeTime(self): self.pub_set_wake_time.publish(rospy.Time(self._widget.absolute_wake_time_obj.dateTime().toTime_t())) def clearWakeTime(self): self.pub_set_wake_time.publish(rospy.Time(0)) def refreshMaxSpeed(self): self.max_speed_dirty = True self.max_speed_known = False def updateGuiCallback(self): # Switch between tabs and full GUI if self.is_currently_tab: if self._widget.height() > 830 and self._widget.width() > 1205: self.is_currently_tab = False self.context_.remove_widget(self._widget) self.initGui('full') else: if self._widget.height() < 810 or self._widget.width() < 1185: self.is_currently_tab = True self.context_.remove_widget(self._widget) self.initGui('tab') # Check connection to base if self.base_connected and (rospy.Time.now() - self.last_joystick_time).to_sec() > 1.0: self.base_connected = False self._widget.disconnected_lbl.setText('<font color=#FF0000>NOT CONNECTED</font>') self._widget.disconnected_lbl.setVisible(True) if not self.base_connected and (rospy.Time.now() - self.last_joystick_time).to_sec() < 1.0: self.base_connected = True # self._widget.disconnected_lbl.setText('') self._widget.disconnected_lbl.setVisible(False) # Update checklists self.updateChecklist(); # Manage 5 second disable of gyro calibration button if not self.cal_enabled: if (rospy.Time.now() - self.cal_time).to_sec() > 5.0: self._widget.gyro_cal_btn.setEnabled(True) self._widget.gyro_cal_btn.setText('Calibrate') self.cal_enabled = True else: self._widget.gyro_cal_btn.setEnabled(False) self._widget.gyro_cal_btn.setText(str(5 - 0.1*floor(10*(rospy.Time.now() - self.cal_time).to_sec()))) # Update joystick graphics if not self.checkJoystickValid(): self.updateCheckStatus(self._widget.joystick_bind_chk, self.NONE) if not self.joystick_bind_status: self._widget.joystick_bind_lbl.setText('') for l in self.joystick_power_ind: l.setVisible(True) self.updateRightStickIndicator(self.stick_ind_range_mid, self.stick_ind_range_mid) self.updateLeftStickIndicator(self.stick_ind_range_mid, self.stick_ind_range_mid) else: self.updateCheckStatus(self._widget.joystick_bind_chk, self.GOOD) self._widget.joystick_bind_lbl.setText('Joystick bound') for l in self.joystick_power_ind: l.setVisible(False) self.updateRightStickIndicator(self.joystick_data[ChannelIndex.CHAN_LATERAL], self.joystick_data[ChannelIndex.CHAN_FORWARD]) self.updateLeftStickIndicator(self.joystick_data[ChannelIndex.CHAN_ROTATE], self.joystick_data[ChannelIndex.CHAN_ENABLE]) if self.joystick_data[ChannelIndex.CHAN_MODE] < self.stick_ind_range_mid: self.mode_ind.setPen(self.cyan_pen) self._widget.modeLabel.setText("0 (Computer)") else: self.mode_ind.setPen(self.magenta_pen) self._widget.modeLabel.setText("1 (Manual)") # Update joystick data table for i in range(len(self.joystick_table_vals)): self.joystick_table_vals[i].setText(str(self.joystick_data[i])) # Update twist data table if self.command_received: self.twist_table_vals[0].setText(str(0.01 * floor(100 * self.current_cmd.linear.x))) self.twist_table_vals[1].setText(str(0.01 * floor(100 * self.current_cmd.linear.y))) self.twist_table_vals[2].setText(str(0.01 * floor(100 * self.current_cmd.angular.z))) else: self.twist_table_vals[0].setText('Not Published') self.twist_table_vals[1].setText('Not Published') self.twist_table_vals[2].setText('Not Published') # Update battery percentage self.battery_label.setText(str(self.battery_percent) + ' %') self.battery_voltage_label.setText(str(0.01 * floor(100 * self.battery_voltage)) + ' V') # Update mode self.mode_label.setText(self.getModeString(self.current_mode)) # Update bumper graphics self.bumperVisibleSwitch(BumperIndex.BUMPER_1F, self.bumper_front_left) self.bumperVisibleSwitch(BumperIndex.BUMPER_2F, self.bumper_front_right) self.bumperVisibleSwitch(BumperIndex.BUMPER_3F, self.bumper_rear_left) self.bumperVisibleSwitch(BumperIndex.BUMPER_4F, self.bumper_rear_right) self.bumper_state_labels[0].setPlainText(str(self.bumper_front_left)) self.bumper_state_labels[1].setPlainText(str(self.bumper_front_right)) self.bumper_state_labels[2].setPlainText(str(self.bumper_rear_left)) self.bumper_state_labels[3].setPlainText(str(self.bumper_rear_right)) # Update gyro cal graphics if self.gyro_cal_status: self.updateCheckStatus(self._widget.gyro_cal_chk, self.GOOD) self._widget.gyro_cal_lbl.setText('Gyro calibrated') else: self.updateCheckStatus(self._widget.gyro_cal_chk, self.BAD) self._widget.gyro_cal_lbl.setText('Gyro NOT calibrated') self._widget.gyro_x_lbl.setText('x: ' + str(1e-5*floor(1e5*self.gyro_x))) self._widget.gyro_y_lbl.setText('y: ' + str(1e-5*floor(1e5*self.gyro_y))) self._widget.gyro_z_lbl.setText('z: ' + str(1e-5*floor(1e5*self.gyro_z))) # Update max speed configuration if not self.max_speed_known: service_name = '/mobility_base/get_max_speed' get_max_speed_srv = rospy.ServiceProxy(service_name, GetMaxSpeed) try: resp = get_max_speed_srv() self.max_speed_known = True self.max_linear_actual = resp.linear self.max_angular_actual = resp.angular if self.max_linear_actual <= 0 or not isfinite(self.max_linear_actual): self._widget.max_linear_lbl.setText('Unlimited') else: self._widget.max_linear_lbl.setText(str(1e-2*round(1e2*self.max_linear_actual))) if self.max_angular_actual <= 0 or not isfinite(self.max_angular_actual): self._widget.max_angular_lbl.setText('Unlimited') else: self._widget.max_angular_lbl.setText(str(1e-2*round(1e2*self.max_angular_actual))) except: pass # print service_name + " doesn't exist" if self.max_speed_dirty: self._widget.max_linear_txt.setText(str(self.max_linear_setting)) self._widget.max_angular_txt.setText(str(self.max_angular_setting)) self.max_speed_dirty = False # Wake time if self.current_wake_time == rospy.Time(0): self._widget.wake_time_lbl.setText('Not Set') else: self._widget.wake_time_lbl.setText(time.strftime('%m/%d/%Y, %H:%M:%S', time.localtime(self.current_wake_time.to_sec()))) def checkJoystickValid(self): 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 def getModeString(self, mode_num): if mode_num == Mode.MODE_ESTOP: return 'MODE_ESTOP' elif mode_num == Mode.MODE_DISABLED: return 'MODE_DISABLED' elif mode_num == Mode.MODE_BATTERY_LIMP_HOME: return 'MODE_BATTERY_LIMP_HOME' elif mode_num == Mode.MODE_BATTERY_CRITICAL: return 'MODE_BATTERY_CRITICAL' elif mode_num == Mode.MODE_WIRELESS: return 'MODE_WIRELESS' elif mode_num == Mode.MODE_TIMEOUT: return 'MODE_TIMEOUT' elif mode_num == Mode.MODE_VELOCITY: return 'MODE_VELOCITY' elif mode_num == Mode.MODE_VELOCITY_RAW: return 'MODE_VELOCITY_RAW' else: return '' def updateChecklist(self): if self.current_mode >= Mode.MODE_TIMEOUT: self.checklist_status[self.BATT_MAN] = self.GOOD self.checklist_status[self.ESTOP_MAN] = self.GOOD self.checklist_status[self.DISABLE_MAN] = self.GOOD self.checklist_status[self.JOYSTICK_MAN] = self.BAD self.checklist_status[self.BATT_COMP] = self.GOOD self.checklist_status[self.ESTOP_COMP] = self.GOOD self.checklist_status[self.DISABLE_COMP] = self.GOOD self.checklist_status[self.JOYSTICK_COMP] = self.GOOD elif self.current_mode == Mode.MODE_WIRELESS: self.checklist_status[self.BATT_MAN] = self.GOOD self.checklist_status[self.ESTOP_MAN] = self.GOOD self.checklist_status[self.DISABLE_MAN] = self.GOOD self.checklist_status[self.JOYSTICK_MAN] = self.GOOD self.checklist_status[self.BATT_COMP] = self.GOOD self.checklist_status[self.ESTOP_COMP] = self.GOOD self.checklist_status[self.DISABLE_COMP] = self.GOOD self.checklist_status[self.JOYSTICK_COMP] = self.BAD elif self.current_mode == Mode.MODE_DISABLED: self.checklist_status[self.BATT_MAN] = self.NONE self.checklist_status[self.ESTOP_MAN] = self.GOOD self.checklist_status[self.DISABLE_MAN] = self.BAD self.checklist_status[self.JOYSTICK_MAN] = self.NONE self.checklist_status[self.BATT_COMP] = self.NONE self.checklist_status[self.ESTOP_COMP] = self.GOOD self.checklist_status[self.DISABLE_COMP] = self.BAD self.checklist_status[self.JOYSTICK_COMP] = self.NONE elif self.current_mode == Mode.MODE_ESTOP: self.checklist_status[self.BATT_MAN] = self.NONE self.checklist_status[self.ESTOP_MAN] = self.BAD self.checklist_status[self.DISABLE_MAN] = self.NONE self.checklist_status[self.JOYSTICK_MAN] = self.NONE self.checklist_status[self.BATT_COMP] = self.NONE self.checklist_status[self.ESTOP_COMP] = self.BAD self.checklist_status[self.DISABLE_COMP] = self.NONE self.checklist_status[self.JOYSTICK_COMP] = self.NONE elif self.current_mode == Mode.MODE_BATTERY_CRITICAL: self.checklist_status[self.BATT_MAN] = self.BAD self.checklist_status[self.ESTOP_MAN] = self.GOOD self.checklist_status[self.DISABLE_MAN] = self.GOOD self.checklist_status[self.JOYSTICK_MAN] = self.NONE self.checklist_status[self.BATT_COMP] = self.BAD self.checklist_status[self.ESTOP_COMP] = self.GOOD self.checklist_status[self.DISABLE_COMP] = self.GOOD self.checklist_status[self.JOYSTICK_COMP] = self.NONE elif self.current_mode == Mode.MODE_BATTERY_LIMP_HOME: self.checklist_status[self.BATT_MAN] = self.GOOD self.checklist_status[self.ESTOP_MAN] = self.GOOD self.checklist_status[self.DISABLE_MAN] = self.GOOD self.checklist_status[self.JOYSTICK_MAN] = self.NONE self.checklist_status[self.BATT_COMP] = self.BAD self.checklist_status[self.ESTOP_COMP] = self.GOOD self.checklist_status[self.DISABLE_COMP] = self.GOOD self.checklist_status[self.JOYSTICK_COMP] = self.NONE # Check if joystick is suppressed by topic if self.joystick_suppressed: self.checklist_status[self.SUPPRESS_COMP] = self.GOOD self.checklist_status[self.DISABLE_COMP] = self.NONE self.checklist_status[self.JOYSTICK_COMP] = self.NONE else: self.checklist_status[self.SUPPRESS_COMP] = self.NONE if (rospy.Time.now() - self.last_suppress_time).to_sec() > self.JOYSTICK_SUPPRESS_PERIOD: self.checklist_status[self.SUPPRESS_MAN] = self.GOOD else: self.checklist_status[self.SUPPRESS_MAN] = self.BAD # Command message received if self.command_received: self.checklist_status[self.CMD_COMP] = self.GOOD else: self.checklist_status[self.CMD_COMP] = self.BAD # Override twist checkbox if mode is in TIMEOUT if self.current_mode == Mode.MODE_TIMEOUT: self.checklist_status[self.CMD_COMP] = self.BAD # Update checklist graphics self.updateCheckStatus(self._widget.batt_man_chk, self.checklist_status[self.BATT_MAN]) self.updateCheckStatus(self._widget.estop_man_chk, self.checklist_status[self.ESTOP_MAN]) self.updateCheckStatus(self._widget.disable_man_chk, self.checklist_status[self.DISABLE_MAN]) self.updateCheckStatus(self._widget.joystick_man_chk, self.checklist_status[self.JOYSTICK_MAN]) self.updateCheckStatus(self._widget.suppress_man_chk, self.checklist_status[self.SUPPRESS_MAN]) self.updateCheckStatus(self._widget.batt_comp_chk, self.checklist_status[self.BATT_COMP]) self.updateCheckStatus(self._widget.estop_comp_chk, self.checklist_status[self.ESTOP_COMP]) self.updateCheckStatus(self._widget.disable_comp_chk, self.checklist_status[self.DISABLE_COMP]) self.updateCheckStatus(self._widget.joystick_comp_chk, self.checklist_status[self.JOYSTICK_COMP]) self.updateCheckStatus(self._widget.suppress_comp_chk, self.checklist_status[self.SUPPRESS_COMP]) self.updateCheckStatus(self._widget.cmd_comp_chk, self.checklist_status[self.CMD_COMP]) self.updateCheckStatus(self._widget.joystick_bind_chk, self.NONE) def updateCheckStatus(self, obj, icon_type): if icon_type == self.GOOD: obj.setPixmap(self.good_icon) elif icon_type == self.BAD: obj.setPixmap(self.bad_icon) else: obj.setPixmap(self.none_icon) def updateTable(self): for i in range(0, len(self.joystick_table_vals)): self.joystick_table_vals[i].setText(55) def recvMode(self, mode_msg): self.current_mode = mode_msg.mode def recvSuppress(self, suppress_msg): self.suppress_dt = rospy.Time.now() - self.last_suppress_time self.last_suppress_time = rospy.Time.now() def recvTwist(self, twist_msg): self.twist_dt = rospy.Time.now() - self.last_twist_time self.last_twist_time = rospy.Time.now() self.current_cmd = twist_msg def recvJoystick(self, joystick_msg): self.joystick_data = joystick_msg.channels; self.last_joystick_time = rospy.Time.now() def recvBumpers(self, bumper_msg): self.bumper_front_left = bumper_msg.front_left self.bumper_front_right = bumper_msg.front_right self.bumper_rear_left = bumper_msg.rear_left self.bumper_rear_right = bumper_msg.rear_right def recvBattery(self, battery_msg): self.battery_percent = battery_msg.percent self.battery_voltage = battery_msg.voltage def recvBindStatus(self, bind_msg): self.joystick_bind_status = bind_msg.data if bind_msg.data: if self.joystick_bind_dot_counter == 0: self._widget.joystick_bind_lbl.setText('Binding.') elif self.joystick_bind_dot_counter == 1: self._widget.joystick_bind_lbl.setText('Binding..') elif self.joystick_bind_dot_counter == 2: self._widget.joystick_bind_lbl.setText('Binding...') self.joystick_bind_dot_counter = (self.joystick_bind_dot_counter + 1) % 3 def recvGyroCalibrated(self, cal_msg): self.gyro_cal_status = cal_msg.data def recvImu(self, imu_msg): self.gyro_x = imu_msg.angular_velocity.x self.gyro_y = imu_msg.angular_velocity.y self.gyro_z = imu_msg.angular_velocity.z def recvWakeTime(self, time_msg): self.current_wake_time = time_msg.data def subscribeTopics(self): sub_joystick = rospy.Subscriber('/mobility_base/joystick_raw', JoystickRaw, self.recvJoystick) sub_suppress = rospy.Subscriber('/mobility_base/suppress_wireless', std_msgs.msg.Empty, self.recvSuppress) sub_twist = rospy.Subscriber('/mobility_base/cmd_vel', Twist, self.recvTwist) sub_mode = rospy.Subscriber('/mobility_base/mode', Mode, self.recvMode) sub_bumpers = rospy.Subscriber('/mobility_base/bumper_states', BumperState, self.recvBumpers) sub_battery = rospy.Subscriber('/mobility_base/battery', BatteryState, self.recvBattery) sub_bind = rospy.Subscriber('/mobility_base/bind_status', std_msgs.msg.Bool, self.recvBindStatus) sub_gyro_calibrated = rospy.Subscriber('/mobility_base/imu/is_calibrated', std_msgs.msg.Bool, self.recvGyroCalibrated) sub_imu = rospy.Subscriber('/mobility_base/imu/data_raw', Imu, self.recvImu) sub_wake_time = rospy.Subscriber('/mobility_base/wake_time', std_msgs.msg.Time, self.recvWakeTime) def advertiseTopics(self): self.pub_start_bind = rospy.Publisher('/mobility_base/bind_start', std_msgs.msg.Empty, queue_size=1) self.pub_stop_bind = rospy.Publisher('/mobility_base/bind_stop', std_msgs.msg.Empty, queue_size=1) self.pub_set_wake_time = rospy.Publisher('/mobility_base/set_wake_time', std_msgs.msg.Time, queue_size=1) def initJoystickGraphics(self): # Pens self.cyan_pen = QPen(QColor(0, 255, 255)) self.magenta_pen = QPen(QColor(255, 0, 255)) self.red_pen = QPen(QColor(255, 0, 0)) self.cyan_pen.setWidth(3) self.magenta_pen.setWidth(3) self.red_pen.setWidth(3) self.stick_ind_l = QGraphicsEllipseItem() self.stick_ind_r = QGraphicsEllipseItem() self.stick_line_l = QGraphicsLineItem() self.stick_line_r = QGraphicsLineItem() self.mode_ind = QGraphicsLineItem() # Left joystick indicator circle px_l = self.stick_ind_lox - self.stick_ind_radius py_l = self.stick_ind_loy - self.stick_ind_radius self.stick_ind_l.setRect(px_l, py_l, 2 * self.stick_ind_radius, 2 * self.stick_ind_radius) self.stick_ind_l.setBrush(QBrush(QColor(255, 0, 0))) self.stick_ind_l.setPen(QPen(QColor(0, 0, 0))) # Right joystick indicator circle px_r = self.stick_ind_rox - self.stick_ind_radius py_r = self.stick_ind_roy - self.stick_ind_radius self.stick_ind_r.setRect(px_r, py_r, 2 * self.stick_ind_radius, 2 * self.stick_ind_radius) self.stick_ind_r.setBrush(QBrush(QColor(255, 0, 0))) self.stick_ind_r.setPen(QPen(QColor(0, 0, 0))) # Left joystick indicator line line_pen = QPen(QColor(255,0,0)) line_pen.setWidth(4) self.stick_line_l.setLine(self.stick_ind_lox, self.stick_ind_loy, self.stick_ind_lox, self.stick_ind_loy) self.stick_line_l.setPen(line_pen) # Right joystick indicator line self.stick_line_r.setLine(self.stick_ind_rox, self.stick_ind_roy, self.stick_ind_rox, self.stick_ind_roy) self.stick_line_r.setPen(line_pen) # Mode indicator line self.mode_ind.setLine(self.mode_ind_x1, self.mode_ind_y1, self.mode_ind_x2, self.mode_ind_y2) self.mode_ind.setPen(self.cyan_pen) # Joystick power indicator self.joystick_power_ind = [] self.joystick_power_ind.append(QGraphicsLineItem(self.power_ind_x1, self.power_ind_y + 20, self.power_ind_x1, self.power_ind_y - 20)) 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)) 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)) 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)) # Populate scene graphics_scene = QGraphicsScene() graphics_scene.addItem(self.stick_ind_l) graphics_scene.addItem(self.stick_ind_r) graphics_scene.addItem(self.stick_line_l) graphics_scene.addItem(self.stick_line_r) graphics_scene.addItem(self.mode_ind) for l in self.joystick_power_ind: l.setPen(self.red_pen) graphics_scene.addItem(l) graphics_scene.setSceneRect(0, 0, self._widget.joystickGraphicsView.width() - 4, self._widget.joystickGraphicsView.height() - 4) self._widget.joystickGraphicsView.setScene(graphics_scene) self._widget.joystickGraphicsView.setBackgroundBrush(QBrush(QImage(os.path.join(rospkg.RosPack().get_path('mobility_base_tools'), 'images', 'dx6ilabels.jpg')))) self._widget.joystickGraphicsView.show() def initBumperGraphics(self): # Pens self.blue_pen = QPen(QColor(0,0,255)) self.blue_pen.setWidth(10) self.bumper_lines = [] # Text state labels self.bumper_state_labels = [QGraphicsTextItem() for i in range(0,4)] for i in range(len(self.bumper_state_labels)): self.bumper_state_labels[i].setFont(QFont('Ubuntu', 14, QFont.Bold)) self.bumper_state_labels[i].setPlainText('00') self.bumper_state_labels[0].setPos(self.bumper_fl_x-10, self.bumper_fl_y + 55) self.bumper_state_labels[1].setPos(self.bumper_fr_x-10, self.bumper_fr_y + 55) self.bumper_state_labels[2].setPos(self.bumper_rl_x-10, self.bumper_rl_y - 80) self.bumper_state_labels[3].setPos(self.bumper_rr_x-10, self.bumper_rr_y - 80) # Bumper indicator lines self.bumperLine(self.bumper_fl_x - 20, self.bumper_fl_y - self.bumper_dy, True) self.bumperLine(self.bumper_fl_x - self.bumper_dx, self.bumper_fl_y - 20, False) self.bumperLine(self.bumper_fl_x + self.bumper_dx, self.bumper_fl_y - 20, False) self.bumperLine(self.bumper_fl_x - 20, self.bumper_fl_y + self.bumper_dy, True) self.bumperLine(self.bumper_fr_x - 20, self.bumper_fr_y - self.bumper_dy, True) self.bumperLine(self.bumper_fr_x - self.bumper_dx, self.bumper_fr_y - 20, False) self.bumperLine(self.bumper_fr_x + self.bumper_dx, self.bumper_fr_y - 20, False) self.bumperLine(self.bumper_fr_x - 20, self.bumper_fr_y + self.bumper_dy, True) self.bumperLine(self.bumper_rl_x - 20, self.bumper_rl_y - self.bumper_dy, True) self.bumperLine(self.bumper_rl_x - self.bumper_dx, self.bumper_rl_y - 20, False) self.bumperLine(self.bumper_rl_x + self.bumper_dx, self.bumper_rl_y - 20, False) self.bumperLine(self.bumper_rl_x - 20, self.bumper_rl_y + self.bumper_dy, True) self.bumperLine(self.bumper_rr_x - 20, self.bumper_rr_y - self.bumper_dy, True) self.bumperLine(self.bumper_rr_x - self.bumper_dx, self.bumper_rr_y - 20, False) self.bumperLine(self.bumper_rr_x + self.bumper_dx, self.bumper_rr_y - 20, False) self.bumperLine(self.bumper_rr_x - 20, self.bumper_rr_y + self.bumper_dy, True) # Populate scene graphics_scene = QGraphicsScene() for bumper in self.bumper_lines: graphics_scene.addItem(bumper) for label in self.bumper_state_labels: graphics_scene.addItem(label) graphics_scene.setSceneRect(0, 0, self._widget.bumperGraphicsView.width() - 4, self._widget.bumperGraphicsView.height() - 4) self._widget.bumperGraphicsView.setScene(graphics_scene) self._widget.bumperGraphicsView.setBackgroundBrush(QBrush(QImage(os.path.join(rospkg.RosPack().get_path('mobility_base_tools'), 'images', 'mb_top.png')))) self._widget.bumperGraphicsView.show() def bumperLine(self, x, y, front): new_line = QGraphicsLineItem() if front: new_line.setLine(x, y, x+40, y) else: new_line.setLine(x, y, x, y+40) new_line.setPen(self.blue_pen) new_line.setVisible(False) self.bumper_lines.append(new_line) def bumperVisibleSwitch(self, idx, bumper_state): if (bumper_state & BumperState.BUMPER_FRONT): self.bumper_lines[idx].setVisible(True) else: self.bumper_lines[idx].setVisible(False) if (bumper_state & BumperState.BUMPER_LEFT): self.bumper_lines[idx+1].setVisible(True) else: self.bumper_lines[idx+1].setVisible(False) if (bumper_state & BumperState.BUMPER_RIGHT): self.bumper_lines[idx+2].setVisible(True) else: self.bumper_lines[idx+2].setVisible(False) if (bumper_state & BumperState.BUMPER_REAR): self.bumper_lines[idx+3].setVisible(True) else: self.bumper_lines[idx+3].setVisible(False) def resetGuiTimer(self): # del self.gui_update_timer self.gui_update_timer = QTimer(self._widget) self.gui_update_timer.setInterval(100) self.gui_update_timer.setSingleShot(False) self.gui_update_timer.timeout.connect(lambda:self.updateGuiCallback()) self.gui_update_timer.start() def spawnFullGui(self): super(DiagnosticGui, self).__init__(self.context_) # Give QObjects reasonable names self.setObjectName('DiagnosticGui') # Create QWidget self._widget = QWidget() # Get path to UI file which should be in the "resource" folder of this package ui_file = os.path.join(rospkg.RosPack().get_path('mobility_base_tools'), 'resource', 'DiagnosticGui.ui') # Extend the widget with all attributes and children from UI file loadUi(ui_file, self._widget) # Give QObjects reasonable names self._widget.setObjectName('DiagnosticGui' + str(self.widget_count)) self.widget_count += 1 # Add widget to the user interface self.context_.add_widget(self._widget) def spawnTabGui(self): super(DiagnosticGui, self).__init__(self.context_) # Give QObjects reasonable names self.setObjectName('DiagnosticGui') # Create QWidget self._widget = QWidget() # Get path to UI file which should be in the "resource" folder of this package ui_file = os.path.join(rospkg.RosPack().get_path('mobility_base_tools'), 'resource', 'DiagnosticGuiTabs.ui') # Extend the widget with all attributes and children from UI file loadUi(ui_file, self._widget) # Give QObjects reasonable names self._widget.setObjectName('DiagnosticGui' + str(self.widget_count)) self.widget_count += 1 # Add widget to the user interface self.context_.add_widget(self._widget) def updateRightStickIndicator(self, lat_val, forward_val): horiz_val = -self.stick_ind_range_factor * (lat_val - self.stick_ind_range_mid) vert_val = -self.stick_ind_range_factor * (forward_val - self.stick_ind_range_mid) r = sqrt(horiz_val * horiz_val + vert_val * vert_val) if r > self.stick_ind_range_pix / 2: r = self.stick_ind_range_pix / 2 ang = atan2(vert_val, horiz_val) px = r * cos(ang) py = r * sin(ang) self.stick_ind_r.setPos(QPoint(px, py)) self.stick_line_r.setLine(self.stick_ind_rox, self.stick_ind_roy, self.stick_ind_rox + px, self.stick_ind_roy + py) def updateLeftStickIndicator(self, yaw_val, enable_val): horiz_val = -self.stick_ind_range_factor * (yaw_val - self.stick_ind_range_mid) vert_val = -self.stick_ind_range_factor * (enable_val - self.stick_ind_range_mid) r = sqrt(horiz_val * horiz_val + vert_val * vert_val) if r > self.stick_ind_range_pix / 2: r = self.stick_ind_range_pix / 2 ang = atan2(vert_val, horiz_val) px = r * cos(ang) py = r * sin(ang) self.stick_ind_l.setPos(QPoint(px, py)) self.stick_line_l.setLine(self.stick_ind_lox, self.stick_ind_loy, self.stick_ind_lox + px, self.stick_ind_loy + py) def shutdown_plugin(self): pass
def initJoystickGraphics(self): # Pens self.cyan_pen = QPen(QColor(0, 255, 255)) self.magenta_pen = QPen(QColor(255, 0, 255)) self.red_pen = QPen(QColor(255, 0, 0)) self.cyan_pen.setWidth(3) self.magenta_pen.setWidth(3) self.red_pen.setWidth(3) self.stick_ind_l = QGraphicsEllipseItem() self.stick_ind_r = QGraphicsEllipseItem() self.stick_line_l = QGraphicsLineItem() self.stick_line_r = QGraphicsLineItem() self.mode_ind = QGraphicsLineItem() # Left joystick indicator circle px_l = self.stick_ind_lox - self.stick_ind_radius py_l = self.stick_ind_loy - self.stick_ind_radius self.stick_ind_l.setRect(px_l, py_l, 2 * self.stick_ind_radius, 2 * self.stick_ind_radius) self.stick_ind_l.setBrush(QBrush(QColor(255, 0, 0))) self.stick_ind_l.setPen(QPen(QColor(0, 0, 0))) # Right joystick indicator circle px_r = self.stick_ind_rox - self.stick_ind_radius py_r = self.stick_ind_roy - self.stick_ind_radius self.stick_ind_r.setRect(px_r, py_r, 2 * self.stick_ind_radius, 2 * self.stick_ind_radius) self.stick_ind_r.setBrush(QBrush(QColor(255, 0, 0))) self.stick_ind_r.setPen(QPen(QColor(0, 0, 0))) # Left joystick indicator line line_pen = QPen(QColor(255,0,0)) line_pen.setWidth(4) self.stick_line_l.setLine(self.stick_ind_lox, self.stick_ind_loy, self.stick_ind_lox, self.stick_ind_loy) self.stick_line_l.setPen(line_pen) # Right joystick indicator line self.stick_line_r.setLine(self.stick_ind_rox, self.stick_ind_roy, self.stick_ind_rox, self.stick_ind_roy) self.stick_line_r.setPen(line_pen) # Mode indicator line self.mode_ind.setLine(self.mode_ind_x1, self.mode_ind_y1, self.mode_ind_x2, self.mode_ind_y2) self.mode_ind.setPen(self.cyan_pen) # Joystick power indicator self.joystick_power_ind = [] self.joystick_power_ind.append(QGraphicsLineItem(self.power_ind_x1, self.power_ind_y + 20, self.power_ind_x1, self.power_ind_y - 20)) 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)) 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)) 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)) # Populate scene graphics_scene = QGraphicsScene() graphics_scene.addItem(self.stick_ind_l) graphics_scene.addItem(self.stick_ind_r) graphics_scene.addItem(self.stick_line_l) graphics_scene.addItem(self.stick_line_r) graphics_scene.addItem(self.mode_ind) for l in self.joystick_power_ind: l.setPen(self.red_pen) graphics_scene.addItem(l) graphics_scene.setSceneRect(0, 0, self._widget.joystickGraphicsView.width() - 4, self._widget.joystickGraphicsView.height() - 4) self._widget.joystickGraphicsView.setScene(graphics_scene) self._widget.joystickGraphicsView.setBackgroundBrush(QBrush(QImage(os.path.join(rospkg.RosPack().get_path('mobility_base_tools'), 'images', 'dx6ilabels.jpg')))) self._widget.joystickGraphicsView.show()