command_widget.py
Go to the documentation of this file.
00001 #!/usr/bin/env python
00002 
00003 # Software License Agreement (BSD License)
00004 #
00005 # Copyright (c) 2015, Tokyo Opensource Robotics Kyokai Association
00006 # All rights reserved.
00007 #
00008 # Redistribution and use in source and binary forms, with or without
00009 # modification, are permitted provided that the following conditions
00010 # are met:
00011 #
00012 #  * Redistributions of source code must retain the above copyright
00013 #    notice, this list of conditions and the following disclaimer.
00014 #  * Redistributions in binary form must reproduce the above
00015 #    copyright notice, this list of conditions and the following
00016 #    disclaimer in the documentation and/or other materials provided
00017 #    with the distribution.
00018 #  * Neither the name of Tokyo Opensource Robotics Kyokai Association (TORK).
00019 #    nor the names of its contributors may be used to endorse or promote
00020 #    products derived from this software without specific prior written permission.
00021 #
00022 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
00023 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00024 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
00025 # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
00026 # COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
00027 # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
00028 # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00029 # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
00030 # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00031 # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
00032 # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00033 # POSSIBILITY OF SUCH DAMAGE.
00034 
00035 import os
00036 try:  # Python2
00037     from urlparse import urlparse
00038 except ImportError:  # Python3
00039     from urllib.parse import urlparse
00040 
00041 from hironx_ros_bridge.hironx_client import HIRONX
00042 from hrpsys import rtm
00043 from hrpsys_ros_bridge.hrpsys_dashboard import HrpsysDashboard
00044 from python_qt_binding import loadUi
00045 from python_qt_binding.QtCore import Qt, Signal
00046 
00047 try: #14.04
00048     from python_qt_binding.QtGui import (QHeaderView, QItemSelectionModel,
00049                                          QWidget)
00050 except: #16.04
00051     from python_qt_binding.QtWidgets import (QHeaderView, QWidget)
00052     from python_qt_binding.QtCore import QItemSelectionModel
00053 
00054 from rosgraph import Master
00055 from rospkg import RosPack
00056 import rospy
00057 from rospy.exceptions import ROSException
00058 import rosservice
00059 from rqt_robot_dashboard.widgets import MenuDashWidget
00060 
00061 PKG_NAME = 'hironx_ros_bridge'
00062 
00063 
00064 class HironxoCommandPanel(QWidget):
00065     '''
00066     Design decisions:
00067 
00068     - joint_state_publisher is dropped, since hrpsys_ros_bridge seems to set
00069     `robot_description` param using COLLADA (see https://goo.gl/aLpILa)
00070     instead of URDF, which joint_state_publisher is not capable of.
00071     '''
00072 
00073     def __init__(self, parent, guicontext):
00074         '''
00075         A GUi panel to list common operation commands for Hironx / NEXTAGE Open robot.
00076 
00077         @param guicontext: The plugin context to create the monitor in.
00078         @type guicontext: qt_gui.plugin_context.PluginContext
00079         '''
00080         super(HironxoCommandPanel, self).__init__()
00081         self._parent = parent
00082         self._guicontext = guicontext
00083 
00084         # RTM Client
00085         rtm.nshost = rospy.get_param('rtmnameserver_host', 'localhost')
00086         rtm.nsport = rospy.get_param('rtmnameserver_port', '15005')
00087         robotname = rospy.get_param('rtmnameserver_robotname', 'HiroNX(Robot)0')
00088         rospy.loginfo('Connecting to RTM nameserver. host={}, port={}, robotname={} using rtmnameserver_{{host,port,robotname}} ROS param'.format(rtm.nshost, rtm.nsport, robotname))
00089 
00090         self._rtm = HIRONX()
00091         self._rtm.init(robotname=robotname, url='')
00092 
00093         rospack = RosPack()
00094         ui_file = os.path.join(rospack.get_path(PKG_NAME), 'resource',
00095                                'hironx_commandpanel_main.ui')
00096         loadUi(ui_file, self, {'HironxoCommandPanel': HironxoCommandPanel})
00097 
00098         self._precision_output = 4  # Default degree order to be used to print values
00099 
00100         # Assign callback methods
00101         self.pushButton_checkEncoders.clicked[bool].connect(self._check_encoders)
00102         self.pushButton_goInitial.clicked[bool].connect(self._go_initial)
00103         self.pushButton_goInitial_factoryval.clicked[bool].connect(self._go_initial_factoryval)
00104         self.pushButton_goOffPose.clicked[bool].connect(self._go_offPose)
00105         self.pushButton_startImpedance.clicked[bool].connect(self._impedance_on)
00106         self.pushButton_stopImpedance.clicked[bool].connect(self._impedance_off)
00107         self.pushButton_actualPose_l.clicked[bool].connect(self._actual_pose_l)
00108         self.pushButton_actualPose_r.clicked[bool].connect(self._actual_pose_r)
00109         self.spinBox_precision_output.valueChanged[int].connect(self._get_precision_output)
00110         self.pushButton_groups.clicked[bool].connect(self._show_groups)
00111 
00112     def get_rosmaster_domain(self):
00113         '''
00114         Workaround for rosgraph.Master.getUri() that does NOT return
00115         a domain name with ".local".
00116         '''
00117         master = Master('/hironxo_command_widget')
00118         #masteruri_http = master.getUri()  # This does not obtain a hostname with ".local", 
00119                                            # regardless ROS_MASTER_URI actually contains it.
00120         masteruri_http = os.environ['ROS_MASTER_URI']
00121         urlparsed = urlparse(masteruri_http)
00122         return urlparsed
00123 
00124     def _print_command(self, command_str):
00125         self.textBrowser_output.append('***Command used***\n\t' + command_str)
00126 
00127     def _get_duration(self):
00128         '''
00129         @rtype float
00130         '''
00131         return float(self.doubleSpinBox_duration.text())
00132 
00133     def _get_precision_output(self):
00134         self._precision_output = self.spinBox_precision_output.value()
00135 
00136     def _get_arm_impedance(self):
00137         '''
00138         @rtype str
00139         @return: Returns a name of arm group that is checked on GUI. None by default.
00140         '''
00141         checked_arm = None
00142         if self.radioButton_impedance_left.isChecked():
00143             checked_arm = 'larm'
00144         elif self.radioButton_impedance_right.isChecked():
00145             checked_arm = 'rarm'
00146         return checked_arm
00147 
00148     def _check_encoders(self):
00149         self._print_command('checkEncoders()')
00150         self._rtm.checkEncoders()
00151 
00152     def _go_initial(self):
00153         self._print_command('goInitial(tm={})'.format(self._get_duration()))
00154         self._rtm.goInitial(tm=self._get_duration())
00155 
00156     def _go_initial_factoryval(self):
00157         self._print_command('goInitial(init_pose_type=1, tm={})'.format(self._get_duration()))
00158         self._rtm.goInitial(init_pose_type=self._rtm.INITPOS_TYPE_FACTORY,
00159                             tm=self._get_duration())
00160 
00161     def _go_offPose(self):
00162         self._print_command('goOffPose(tm={})'.format(self._get_duration()))
00163         self._rtm.goOffPose(tm=self._get_duration())
00164 
00165     def _impedance_on_off(self, do_on=True):
00166         '''
00167         Start/stop impedance control for the specified arm group.
00168         Arm group to operate impedance control is automatically obtained from
00169         GUI internally within this method.
00170         @raise AttributeError: When no arm group is specified.
00171         @type do_on: bool
00172         @param do_on: On/off of impedance control
00173         '''
00174         armgroup = self._get_arm_impedance()
00175         if not armgroup:
00176             raise AttributeError('No arm is specified for impedance control to start.')
00177         if do_on:
00178             self._print_command('startImpedance({})'.format(armgroup))
00179             self._rtm.startImpedance(armgroup)
00180         elif not do_on:
00181             self._print_command('stopImpedance({})'.format(armgroup))
00182             self._rtm.stopImpedance(armgroup)
00183 
00184     def _impedance_on(self):
00185         self._impedance_on_off()
00186 
00187     def _impedance_off(self):
00188         self._impedance_on_off(do_on=False)
00189 
00190     def _show_actual_pose(self, list_pose):
00191         '''
00192         @type list_pose: [str]
00193         @param list_pose: list of str that represent angles (in radian)
00194         '''
00195         # Print the section line. This creates '---- ---- ---- ---- '
00196         section_line_piece = '-'
00197         text_single_line = section_line_piece * self._precision_output + '\t'
00198         self.textBrowser_output.append(text_single_line * 4)
00199 
00200         text_single_line = ''
00201         i = 0
00202         for fl in list_pose:
00203             val = str(round(fl, self._precision_output))
00204 
00205             # Format the diagonal
00206             text_single_line += val
00207             print('DEBUG) #{}: text_single_line: {}'.format(i, text_single_line))
00208             # If num of elements in a single line reaches 4,
00209             # or if cursor reaches the end of the list.
00210             # Also, We want to add the 1st element into the 1st line.
00211             if (i != 0 and i % 4 == 3) or i+1 == len(list_pose):
00212                 self.textBrowser_output.append(text_single_line)
00213                 text_single_line = ''  # Clear the text for a single line
00214             else:
00215                 text_single_line += '\t'
00216             i += 1
00217 
00218     def _actual_pose_l(self):
00219         target_joint = 'LARM_JOINT5'
00220         self._print_command('getCurrentPose({})'.format(target_joint))
00221         self._show_actual_pose(self._rtm.getCurrentPose(target_joint))
00222 
00223     def _actual_pose_r(self):
00224         target_joint = 'LARM_JOINT5'
00225         self._print_command('getCurrentPose({})'.format(target_joint))
00226         self._show_actual_pose(self._rtm.getCurrentPose(target_joint))
00227 
00228     def _show_groups(self):
00229         groups = self._rtm.Groups
00230         text = ''
00231         for g in groups:
00232             text += g[0]
00233             str_elems = ''.join(str('\t' + e + '\n') for e in g[1])
00234             text += str_elems
00235 
00236         self._print_command('Groups')
00237         self.textBrowser_output.append(text)


hironx_ros_bridge
Author(s): Kei Okada , Isaac I.Y. Saito
autogenerated on Thu Feb 21 2019 03:42:37