Go to the documentation of this file.00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035 import os
00036 try:
00037 from urlparse import urlparse
00038 except ImportError:
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:
00048 from python_qt_binding.QtGui import (QHeaderView, QItemSelectionModel,
00049 QWidget)
00050 except:
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
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
00099
00100
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
00119
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
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
00206 text_single_line += val
00207 print('DEBUG) #{}: text_single_line: {}'.format(i, text_single_line))
00208
00209
00210
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 = ''
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)