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 math
00036 import numpy
00037 import os
00038 import time
00039
00040 import roslib; roslib.load_manifest("hrpsys")
00041 from hrpsys.hrpsys_config import *
00042 import OpenHRP
00043 import OpenRTM_aist
00044 import OpenRTM_aist.RTM_IDL
00045 import rtm
00046 from waitInput import waitInputConfirm, waitInputSelect
00047
00048
00049 SWITCH_ON = OpenHRP.RobotHardwareService.SWITCH_ON
00050 SWITCH_OFF = OpenHRP.RobotHardwareService.SWITCH_OFF
00051 _MSG_ASK_ISSUEREPORT = 'Your report to ' + \
00052 'https://github.com/start-jsk/rtmros_hironx/issues ' + \
00053 'about the issue you are seeing is appreciated.'
00054
00055
00056 class HIRONX(HrpsysConfigurator):
00057 '''
00058 @see: <a href = "https://github.com/fkanehiro/hrpsys-base/blob/master/python/hrpsys_config.py">HrpsysConfigurator</a>
00059
00060 This class holds methods that are specific to Kawada Industries' dual-arm
00061 robot called Hiro.
00062
00063 For the API doc for the derived methods, please see the parent
00064 class via the link above; nicely formatted api doc web page
00065 isn't available yet (discussed in
00066 https://github.com/fkanehiro/hrpsys-base/issues/268).
00067 '''
00068
00069 Groups = [['torso', ['CHEST_JOINT0']],
00070 ['head', ['HEAD_JOINT0', 'HEAD_JOINT1']],
00071 ['rarm', ['RARM_JOINT0', 'RARM_JOINT1', 'RARM_JOINT2',
00072 'RARM_JOINT3', 'RARM_JOINT4', 'RARM_JOINT5']],
00073 ['larm', ['LARM_JOINT0', 'LARM_JOINT1', 'LARM_JOINT2',
00074 'LARM_JOINT3', 'LARM_JOINT4', 'LARM_JOINT5']]]
00075
00076 '''
00077 For OffPose and _InitialPose, the angles of each joint are listed in the
00078 ordered as defined in Groups variable.'''
00079 OffPose = [[0], [0, 0],
00080 [25, -139, -157, 45, 0, 0],
00081 [-25, -139, -157, -45, 0, 0],
00082 [0, 0, 0, 0],
00083 [0, 0, 0, 0]]
00084
00085 _InitialPose = [[0], [0, 0],
00086 [-0.6, 0, -100, 15.2, 9.4, 3.2],
00087 [0.6, 0, -100, -15.2, 9.4, -3.2],
00088 [0, 0, 0, 0],
00089 [0, 0, 0, 0]]
00090
00091
00092
00093 _InitialPose_Factory = [[0], [0, 0],
00094 [-0, 0, -130, 0, 0, 0],
00095 [0, 0, -130, 0, 0, 0],
00096 [0, 0, 0, 0],
00097 [0, 0, 0, 0]]
00098 INITPOS_TYPE_EVEN = 0
00099 INITPOS_TYPE_FACTORY = 1
00100
00101 HandGroups = {'rhand': [2, 3, 4, 5], 'lhand': [6, 7, 8, 9]}
00102
00103 RtcList = []
00104
00105
00106 sc = None
00107 sc_svc = None
00108
00109 def init(self, robotname="HiroNX(Robot)0", url=""):
00110 '''
00111 Calls init from its superclass, which tries to connect RTCManager,
00112 looks for ModelLoader, and starts necessary RTC components. Also runs
00113 config, logger.
00114 Also internally calls setSelfGroups().
00115
00116 @type robotname: str
00117 @type url: str
00118 '''
00119 HrpsysConfigurator.init(self, robotname=robotname, url=url)
00120 self.setSelfGroups()
00121
00122 def goOffPose(self, tm=7):
00123 '''
00124 Move arms to the predefined (as member variable) pose where robot can
00125 be safely turned off.
00126
00127 @type tm: float
00128 @param tm: Second to complete.
00129 '''
00130 for i in range(len(self.Groups)):
00131 self.setJointAnglesOfGroup(self.Groups[i][0], self.OffPose[i], tm,
00132 wait=False)
00133 for i in range(len(self.Groups)):
00134 self.seq_svc.waitInterpolationOfGroup(self.Groups[i][0])
00135 self.servoOff(wait=False)
00136
00137 def goInitial(self, tm=7, wait=True, init_pose_type=0):
00138 '''
00139 Move arms to the predefined (as member variable) "initialized" pose.
00140
00141 @type tm: float
00142 @param tm: Second to complete.
00143 @type wait: bool
00144 @param wait: If true, SequencePlayer.waitInterpolationOfGroup gets run.
00145 (TODO: Elaborate what this means...Even after having taken
00146 a look at its source code I can't tell what it means.)
00147 @type init_pose_type: int
00148 @param init_pose_type: 0: default init pose (specified as _InitialPose)
00149 1: factory init pose (specified as
00150 _InitialPose_Factory)
00151 '''
00152 if init_pose_type == self.INITPOS_TYPE_FACTORY:
00153 _INITPOSE = self._InitialPose_Factory
00154 else:
00155 _INITPOSE = self._InitialPose
00156
00157 ret = True
00158 for i in range(len(self.Groups)):
00159
00160 print self.configurator_name, 'self.setJointAnglesOfGroup(', \
00161 self.Groups[i][0], ',', _INITPOSE[i], ', ', tm, \
00162 ',wait=False)'
00163 ret &= self.setJointAnglesOfGroup(self.Groups[i][0],
00164 _INITPOSE[i],
00165 tm, wait=False)
00166 if wait:
00167 for i in range(len(self.Groups)):
00168 self.seq_svc.waitInterpolationOfGroup(self.Groups[i][0])
00169 return ret
00170
00171 def getRTCList(self):
00172 '''
00173 @see: HrpsysConfigurator.getRTCList
00174
00175 @rtype [[str]]
00176 @rerutrn List of available components. Each element consists of a list
00177 of abbreviated and full names of the component.
00178 '''
00179 return [
00180 ['seq', "SequencePlayer"],
00181 ['sh', "StateHolder"],
00182 ['fk', "ForwardKinematics"],
00183 ['el', "SoftErrorLimiter"],
00184
00185 ['sc', "ServoController"],
00186 ['log', "DataLogger"]
00187 ]
00188
00189
00190
00191
00192
00193
00194
00195
00196 def HandOpen(self, hand=None, effort=None):
00197 '''
00198 Set the stretch between two fingers of the specified hand as
00199 hardcoded value (100mm), by internally calling self.setHandWidth.
00200
00201 @type hand: str
00202 @param hand: Name of the hand joint group. In the default
00203 setting of HIRONX, hand joint groups are defined
00204 in member 'HandGroups' where 'lhand' and 'rhand'
00205 are added.
00206 @type effort: int
00207 '''
00208 self.setHandWidth(hand, 100, effort=effort)
00209
00210 def HandClose(self, hand=None, effort=None):
00211 '''
00212 Close 2-finger hand, by internally calling self.setHandWidth
00213 setting 0 width.
00214
00215 @type hand: str
00216 @param hand: Name of the hand joint group. In the default
00217 setting of HIRONX, hand joint groups are defined
00218 in member 'HandGroups' where 'lhand' and 'rhand'
00219 are added.
00220 @type effort: int
00221 '''
00222 self.setHandWidth(hand, 0, effort=effort)
00223
00224 def setHandJointAngles(self, hand, angles, tm=1):
00225 '''
00226 @type hand: str
00227 @param hand: Name of the hand joint group. In the default
00228 setting of HIRONX, hand joint groups are defined
00229 in member 'HandGroups' where 'lhand' and 'rhand'
00230 are added.
00231 @type angles: OpenHRP::ServoControllerService::dSequence.
00232 @param angles: List of (TODO: document). Elements are in degree.
00233 @param tm: Time to complete the task.
00234 '''
00235 self.sc_svc.setJointAnglesOfGroup(hand, angles, tm)
00236
00237 def setHandEffort(self, effort=100):
00238 '''
00239 Set maximum torque for all existing hand components.
00240 @type effort: int
00241 '''
00242
00243 for i in [v for vs in self.HandGroups.values() for v in vs]:
00244 self.sc_svc.setMaxTorque(i, effort)
00245
00246 def setHandWidth(self, hand, width, tm=1, effort=None):
00247 '''
00248 @type hand: str
00249 @param hand: Name of the hand joint group. In the default
00250 setting of HIRONX, hand joint groups are defined
00251 in member 'HandGroups' where 'lhand' and 'rhand'
00252 are added.
00253 @param width: Max=100.
00254 @param tm: Time to complete the move.
00255 @type effort: int
00256 @param effort: Passed to self.setHandEffort if set. Not set by default.
00257 '''
00258 if effort:
00259 self.setHandEffort(effort)
00260 if hand:
00261 self.setHandJointAngles(hand, self.hand_width2angles(width), tm)
00262 else:
00263 for h in self.HandGroups.keys():
00264 self.setHandJointAngles(h, self.hand_width2angles(width), tm)
00265
00266 def moveHand(self, hand, av, tm=1):
00267 '''
00268 Negate the angle value for {2, 3, 6, 7}th element in av.
00269
00270 @type hand: str
00271 @param hand: Specifies hand. (TODO: List the possible values. Should be
00272 listed in setHandJointAngles so just copy from its doc.)
00273 @type av: [int]
00274 @param av: angle of each joint of the specified arm
00275 (TODO: need verified. Also what's the length of the list?)
00276 @param tm: Time in second to complete the work.
00277 '''
00278 for i in [2, 3, 6, 7]:
00279 av[i] = -av[i]
00280 self.setHandJointAngles(hand, av, tm)
00281
00282 def hand_width2angles(self, width):
00283 '''
00284 TODO: Needs documented what this method does.
00285
00286 @type width: float
00287 @return: None if the given width is invalid.
00288 '''
00289 safetyMargin = 3
00290 l1, l2 = (41.9, 19)
00291
00292 if width < 0.0 or width > (l1 + l2 - safetyMargin) * 2:
00293 return None
00294
00295 xPos = width / 2.0 + safetyMargin
00296 a2Pos = xPos - l2
00297 a1radH = math.acos(a2Pos / l1)
00298 a1rad = math.pi / 2.0 - a1radH
00299
00300 return a1rad, -a1rad, -a1rad, a1rad
00301
00302 def setSelfGroups(self):
00303 '''
00304 Set to the hrpsys.SequencePlayer the groups of links and joints that
00305 are statically defined as member variables (Groups) within this class.
00306
00307 That said, override Groups variable if you prefer link and joint
00308 groups set differently.
00309 '''
00310
00311
00312 for item in self.Groups:
00313 self.seq_svc.addJointGroup(item[0], item[1])
00314 for k, v in self.HandGroups.iteritems():
00315 if self.sc_svc:
00316 self.sc_svc.addJointGroup(k, v)
00317
00318 def getActualState(self):
00319 '''
00320 Returns the physical state of robot.
00321
00322 @rtype: <a href = "http://hrpsys-base.googlecode.com/svn/doc/df/d17/structOpenHRP_1_1RobotHardwareService_1_1RobotState.html">OpenHRP::RobotHardwareService::RobotState</a>
00323 @return: Robot's hardware status object that contains the following
00324 variables accessible: angle, command, torque, servoState,
00325 force, rateGyro, accel, voltage, current. See the api doc
00326 of the class for more detail. Each variable is accessible by
00327 like this for example:
00328
00329 servostate= robot.getActualState().servoState
00330 '''
00331
00332
00333
00334 return self.rh_svc.getStatus()
00335
00336 def isCalibDone(self):
00337 '''
00338 Check whether joints have been calibrated.
00339 @rtype bool
00340 '''
00341 if self.simulation_mode:
00342 return True
00343 else:
00344 rstt = self.rh_svc.getStatus()
00345 for item in rstt.servoState:
00346 if not item[0] & 1:
00347 return False
00348 return True
00349
00350 def isServoOn(self, jname='any'):
00351 '''
00352 Check whether servo control has been turned on.
00353 @type jname: str
00354 @param jname: Name of a link (that can be obtained by "hiro.Groups"
00355 as lists of groups).
00356 @rtype bool
00357 '''
00358
00359 if self.simulation_mode:
00360 return True
00361 else:
00362 s_s = self.getActualState().servoState
00363 if jname.lower() == 'any' or jname.lower() == 'all':
00364 for s in s_s:
00365
00366 if (s[0] & 2) == 0:
00367 return False
00368 else:
00369 jid = eval('self.' + jname)
00370 print self.configurator_name, s_s[jid]
00371 if s_s[jid][0] & 1 == 0:
00372 return False
00373 return True
00374 return False
00375
00376 def flat2Groups(self, flatList):
00377 '''
00378 @type flatList: [int]
00379 @param flatList: single dimension list, with its length depends on
00380 'Groups' variable defined within this class. Excessive
00381 elements will be dropped (see example below in @return)
00382
00383 eg. If the number of joints of the robot is 15,
00384 len(flatList) should be 15.
00385 @rtype: [[]]
00386 @return: 2-dimensional list that has the same format with
00387 'Groups' variable.
00388
00389 eg.
00390 ipython> flatlist = [0, 10, 20, 30, 40, 50, 60, 70, 80, 90,
00391 100, 110, 120, 130, 140, 150]
00392 ipython> robot.flat2Groups(flatlist)
00393 [[0], [10, 20],
00394 [30, 40, 50, 60, 70, 80],
00395 [90, 100, 110, 120, 130, 140]]
00396
00397 '''
00398 retList = []
00399 index = 0
00400 for group in self.Groups:
00401 joint_num = len(group[1])
00402 retList.append(flatList[index: index + joint_num])
00403 index += joint_num
00404 return retList
00405
00406 def servoOn(self, jname='all', destroy=1, tm=3):
00407 '''
00408 Turn on servo motors at joint specified.
00409 Joints need to be calibrated (otherwise error returns).
00410
00411 @type jname: str
00412 @param jname: The value 'all' works iteratively for all servos.
00413 @param destroy: Not used.
00414 @type tm: float
00415 @param tm: Second to complete.
00416 @rtype: int
00417 @return: 1 or -1 indicating success or failure, respectively.
00418 '''
00419
00420 if not self.isCalibDone():
00421 waitInputConfirm('!! Calibrate Encoders with checkEncoders first !!\n\n')
00422 return -1
00423
00424
00425 if self.isServoOn():
00426 return 1
00427
00428
00429 if jname == '':
00430 jname = 'all'
00431
00432
00433
00434 try:
00435 waitInputConfirm(\
00436 '!! Robot Motion Warning (SERVO_ON) !!\n\n'
00437 'Confirm RELAY switched ON\n'
00438 'Push [OK] to switch servo ON(%s).' % (jname))
00439 except:
00440 self.rh_svc.power('all', SWITCH_OFF)
00441 raise
00442
00443
00444
00445 try:
00446
00447 self.seq_svc.removeJointGroup("larm")
00448 self.seq_svc.removeJointGroup("rarm")
00449 self.seq_svc.removeJointGroup("head")
00450 self.seq_svc.removeJointGroup("torso")
00451 except:
00452 print(self.configurator_name,
00453 'Exception during servoOn while removing JoingGroup. ' +
00454 _MSG_ASK_ISSUEREPORT)
00455 try:
00456
00457 self.setSelfGroups()
00458 except:
00459 print(self.configurator_name,
00460 'Exception during servoOn while removing setSelfGroups. ' +
00461 _MSG_ASK_ISSUEREPORT)
00462
00463 try:
00464 self.goActual()
00465 time.sleep(0.1)
00466 self.rh_svc.servo(jname, SWITCH_ON)
00467 time.sleep(2)
00468
00469 if not self.isServoOn(jname):
00470 print self.configurator_name, 'servo on failed.'
00471 raise
00472 except:
00473 print self.configurator_name, 'exception occured'
00474
00475 try:
00476 angles = self.flat2Groups(map(numpy.rad2deg,
00477 self.getActualState().angle))
00478 print 'Move to Actual State, Just a minute.'
00479 for i in range(len(self.Groups)):
00480 self.setJointAnglesOfGroup(self.Groups[i][0], angles[i], tm,
00481 wait=False)
00482 for i in range(len(self.Groups)):
00483 self.seq_svc.waitInterpolationOfGroup(self.Groups[i][0])
00484 except:
00485 print self.configurator_name, 'post servo on motion trouble'
00486
00487
00488 print 'Turn on Hand Servo'
00489 if self.sc_svc:
00490 self.sc_svc.servoOn()
00491
00492 return 1
00493
00494 def servoOff(self, jname='all', wait=True):
00495 '''
00496 @type jname: str
00497 @param jname: The value 'all' works iteratively for all servos.
00498 @type wait: bool
00499 @rtype: int
00500 @return: 1 = all arm servo off. 2 = all servo on arms and hands off.
00501 -1 = Something wrong happened.
00502 '''
00503
00504 if self.simulation_mode:
00505 print self.configurator_name, 'omit servo off'
00506 return 0
00507
00508 print 'Turn off Hand Servo'
00509 if self.sc_svc:
00510 self.sc_svc.servoOff()
00511
00512 if not self.isServoOn(jname):
00513 if jname.lower() == 'all':
00514 self.rh_svc.power('all', SWITCH_OFF)
00515 return 1
00516
00517
00518 if jname == '':
00519 jname = 'all'
00520
00521 if wait:
00522 waitInputConfirm(
00523 '!! Robot Motion Warning (Servo OFF)!!\n\n'
00524 'Push [OK] to servo OFF (%s).' % (jname))
00525
00526 try:
00527 self.rh_svc.servo('all', SWITCH_OFF)
00528 time.sleep(0.2)
00529 if jname == 'all':
00530 self.rh_svc.power('all', SWITCH_OFF)
00531
00532
00533 print 'Turn off Hand Servo'
00534 if self.sc_svc:
00535 self.sc_svc.servoOff()
00536
00537 return 2
00538 except:
00539 print self.configurator_name, 'servo off: communication error'
00540 return -1
00541
00542 def checkEncoders(self, jname='all', option=''):
00543 '''
00544 Run the encoder checking sequence for specified joints,
00545 run goActual to adjust the direction values, and then turn servos on.
00546
00547 @type jname: str
00548 @param jname: The value 'all' works iteratively for all servos.
00549 @type option: str
00550 @param option: Possible values are follows (w/o double quote):\
00551 "-overwrite": Overwrite calibration value.
00552 '''
00553 if self.isServoOn():
00554 waitInputConfirm('Servo must be off for calibration')
00555 return
00556
00557 elif self.isCalibDone():
00558 waitInputConfirm('System has been calibrated')
00559 return
00560
00561 self.rh_svc.power('all', SWITCH_ON)
00562 msg = '!! Robot Motion Warning !!\n'\
00563 'Turn Relay ON.\n'\
00564 'Then Push [OK] to '
00565 if option == '-overwrite':
00566 msg = msg + 'calibrate(OVERWRITE MODE) '
00567 else:
00568 msg = msg + 'check '
00569
00570 if jname == 'all':
00571 msg = msg + 'the Encoders of all.'
00572 else:
00573 msg = msg + 'the Encoder of the Joint "' + jname + '".'
00574
00575 try:
00576 waitInputConfirm(msg)
00577 except:
00578 print "If you're connecting to the robot from remote, " + \
00579 "make sure tunnel X (eg. -X option with ssh)."
00580 self.rh_svc.power('all', SWITCH_OFF)
00581 return 0
00582
00583 print self.configurator_name, 'calib-joint ' + jname + ' ' + option
00584 self.rh_svc.initializeJointAngle(jname, option)
00585 print self.configurator_name, 'done'
00586 self.rh_svc.power('all', SWITCH_OFF)
00587 self.goActual()
00588 time.sleep(0.1)
00589 self.rh_svc.servo(jname, SWITCH_ON)
00590
00591
00592 print 'Turn on Hand Servo'
00593 if self.sc_svc:
00594 self.sc_svc.servoOn()