Skip to content

Commit ea48d9e

Browse files
committed
[ros_bridge] getRTCList to accept custom list of RTCs.
This allows the downstream `nextage_ros_bridge` to add a patch to fix tork-a/rtmros_nextage#308.
1 parent 0541637 commit ea48d9e

File tree

3 files changed

+108
-33
lines changed

3 files changed

+108
-33
lines changed

hironx_ros_bridge/scripts/hironx.py

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -56,23 +56,16 @@
5656
' this script, but can use RTM. To use ROS, do not forget' \
5757
' to run rosbridge. How to do so? --> http://wiki.ros.org/rtmros_nextage/Tutorials/Operating%20Hiro%2C%20NEXTAGE%20OPEN'
5858

59-
RTC_LIST = [
60-
['seq', "SequencePlayer"],
61-
['sh', "StateHolder"],
62-
['fk', "ForwardKinematics"],
63-
['ic', "ImpedanceController"],
64-
['el', "SoftErrorLimiter"],
65-
# ['co', "CollisionDetector"],
66-
['sc', "ServoController"],
67-
['log', "DataLogger"],]
59+
# The default RTCs for Hironx
60+
RTC_LIST = 'seq, sh, fk, ic, el, sc, log'
6861

6962
if __name__ == '__main__':
7063
parser = argparse.ArgumentParser(description='hiro command line interpreters')
7164
parser.add_argument('--host', help='corba name server hostname')
7265
parser.add_argument('--port', help='corba name server port number')
7366
parser.add_argument('--modelfile', help='robot model file nmae')
7467
parser.add_argument('--robot', help='robot modlule name (RobotHardware0 for real robot, Robot()')
75-
parser.add_argument('--rtcs', help='RT components to activate. If nothing passed then default value will be used.')
68+
parser.add_argument('--rtcs', help="RT components to activate. If nothing passed then default value will be used. Example: '{}'".format(RTC_LIST))
7669
args, unknown = parser.parse_known_args()
7770
unknown = [u for u in unknown if u[:2] != '__'] # filter out ros arguments
7871

hironx_ros_bridge/src/hironx_ros_bridge/hironx_client.py

Lines changed: 62 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -307,7 +307,10 @@ class via the link above; nicely formatted api doc web page
307307

308308
HandGroups = {'rhand': [2, 3, 4, 5], 'lhand': [6, 7, 8, 9]}
309309

310-
_RTClist = [
310+
# This shouldn't be accessed once turned to True during `init` method.
311+
is_rtc_activated = False
312+
313+
_RTC_list = [
311314
['seq', "SequencePlayer"],
312315
['sh', "StateHolder"],
313316
['fk', "ForwardKinematics"],
@@ -318,6 +321,9 @@ class via the link above; nicely formatted api doc web page
318321
['log', "DataLogger"],
319322
]
320323

324+
# List of the name of RT Components that hrpsys requires at minimum.
325+
_RTC_NAME_MINREQ = ['seq', 'sh', 'fk']
326+
321327
# servo controller (grasper)
322328
sc = None
323329
sc_svc = None
@@ -328,7 +334,7 @@ class via the link above; nicely formatted api doc web page
328334
"the function call was successful, since not " +
329335
"all methods internally called return status")
330336

331-
def init(self, robotname="HiroNX(Robot)0", url="", rtcs=_RTClist):
337+
def init(self, robotname="HiroNX(Robot)0", url="", rtcs=None):
332338
'''
333339
Calls init from its superclass, which tries to connect RTCManager,
334340
looks for ModelLoader, and starts necessary RTC components. Also runs
@@ -337,11 +343,10 @@ def init(self, robotname="HiroNX(Robot)0", url="", rtcs=_RTClist):
337343
338344
@type robotname: str
339345
@type url: str
340-
@type rtcs: [[str, str]]
341-
@param rtcs: List of list of RTC names. Each inner list consists of
342-
'SHORTENED' name and the 'FULLNAME'.
346+
@type rtcs: [str]
347+
@param rtcs: List of abbreviated RTC names.
343348
344-
example: [['seq', "SequencePlayer"], ['sh', "StateHolder"],,,]
349+
example: ['seq', 'sh',,,]
345350
'''
346351
# reload for hrpsys 315.1.8
347352
print(self.configurator_name + "waiting ModelLoader")
@@ -366,10 +371,8 @@ def init(self, robotname="HiroNX(Robot)0", url="", rtcs=_RTClist):
366371
# HrpsysConfigurator.init(self, robotname=robotname, url=url)
367372
self.sensors = self.getSensors(url)
368373

369-
if rtcs:
370-
self._RTClist = rtcs
371374
# all([rtm.findRTC(rn[0], rtm.rootnc) for rn in self.getRTCList()]) # not working somehow...
372-
if set([rn[0] for rn in self.getRTCList()]).issubset(set([x.name() for x in self.ms.get_components()])) :
375+
if set([rn[0] for rn in self.getRTCList(rtcs)]).issubset(set([x.name() for x in self.ms.get_components()])) :
373376
print(self.configurator_name + "hrpsys components are already created and running")
374377
self.findComps(max_timeout_count=0, verbose=True)
375378
else:
@@ -450,24 +453,68 @@ def goInitial(self, tm=7, wait=True, init_pose_type=0):
450453
self.seq_svc.waitInterpolationOfGroup(self.Groups[i][0])
451454
return ret
452455

453-
def getRTCList(self):
456+
def getRTCList(self, rtcs_str=None):
454457
'''
458+
@summary: Return the list of activated RT components. As opposed to
459+
its naming, this also:
460+
1) activate an rmfo (stands for "remove force offset")
461+
RTC.
462+
2) selectively activate RTCs passed by rtcs_str. This is
463+
possible ONLY during the initialization process done
464+
by `init` method.
455465
@see: HrpsysConfigurator.getRTCList
456466
467+
@type rtcs_str: str
468+
@param rtcs_str: A single str for a set of abbreviated names of RTCs,
469+
each of which is comma-separated. This is possible
470+
ONLY during the initialization process done by
471+
`init` method.
472+
example: "seq, sh, fk, ic, el, sc, log"
457473
@rtype [[str]]
458-
@rerutrn List of available components. Each element consists of a list
474+
@return List of available components. Each element consists of a list
459475
of abbreviated and full names of the component.
476+
@raise TypeError: When rtcs_str isn't a string.
477+
@raise ValueError: When rtcs_str does not contain minimum
478+
required RTCs.
460479
'''
461-
if hasattr(self, 'rmfo'):
480+
if rtcs_str:
481+
if self.is_rtc_activated:
482+
print('RTCs are already activated. Skipping the passed request: {}'.format(rtcs_str))
483+
else:
484+
if not isinstance(rtcs_str, basestring):
485+
raise TypeError('rtcs_str needs to be string.')
486+
# Set a new list of RTCs
487+
new_rtcs = []
488+
# Separate by comma and remove whitespace.
489+
rtcs_req_list = [x.strip() for x in rtcs_str.split(",")]
490+
# Check if minimum required RTCs are passed.
491+
if not all(x in rtcs_req_list for x in self._RTC_NAME_MINREQ):
492+
raise ValueError('{} are required at minimum'.format(
493+
self._RTC_NAME_MINREQ))
494+
for rtc_requested in rtcs_req_list:
495+
for elem in self._RTC_list:
496+
if elem[0] == rtc_requested:
497+
new_rtcs.append(elem)
498+
break
499+
self._RTC_list = new_rtcs
500+
self.is_rtc_activated = True
501+
502+
is_rmfo_initiated = False
503+
# For some reason using built-in "any" method yields
504+
# `TypeError: 'module' object is not callable`, so do the iteration.
505+
for rtc_list in self._RTC_list:
506+
if 'rmfo' in rtc_list:
507+
is_rmfo_initiated = True
508+
if hasattr(self, 'rmfo') and not is_rmfo_initiated:
462509
self.ms.load("RemoveForceSensorLinkOffset")
463510
self.ms.load("AbsoluteForceSensor")
464511
if "RemoveForceSensorLinkOffset" in self.ms.get_factory_names():
465-
self._RTClist.append(['rmfo', "RemoveForceSensorLinkOffset"])
512+
self._RTC_list.append(['rmfo', "RemoveForceSensorLinkOffset"])
466513
elif "AbsoluteForceSensor" in self.ms.get_factory_names():
467-
self._RTClist.append(['rmfo', "AbsoluteForceSensor"])
514+
self._RTC_list.append(['rmfo', "AbsoluteForceSensor"])
468515
else:
469516
print "Component rmfo is not loadable."
470-
return self._RTClist
517+
return self._RTC_list
471518

472519
# hand interface
473520
# effort: 1~100[%]

hironx_ros_bridge/test/test_hironx_client.py

Lines changed: 43 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -47,24 +47,41 @@ class TestHiroClient(TestHiro):
4747
['fk', "ForwardKinematics"],
4848
['ic', "ImpedanceController"],
4949
['el', "SoftErrorLimiter"],
50-
# ['co', "CollisionDetector"],
5150
['sc', "ServoController"],
5251
['log', "DataLogger"],
52+
# rmfo will be automatically added in getRTCList.
53+
['rmfo', 'RemoveForceSensorLinkOffset']
5354
]
5455

5556
_RTC_LIST_CUSTOM = [
5657
['seq', "SequencePlayer"],
5758
['sh', "StateHolder"],
5859
['fk', "ForwardKinematics"],
59-
['el', "SoftErrorLimiter"],
60-
['co', "CollisionDetector"],
61-
['log', "DataLogger"],
60+
['rmfo', 'RemoveForceSensorLinkOffset']
6261
]
6362

63+
def _compare_rtclist_twodim(self, twodim_list_a, twodim_list_b):
64+
'''
65+
Compare the first element in all elements of the 2nd list.
66+
E.g. For [['a0', 'a1'], ['b0', 'b1'],..., ['n0', 'n1']], this method
67+
checks a0, b0, n0
68+
@rtype bool
69+
'''
70+
return set([a[0] for a in twodim_list_a]) == set(
71+
[b[0] for b in twodim_list_b])
72+
6473
def test_getRTCList(self):
65-
self.assertListEqual(self.robot.getRTCList(), self._RTC_LIST)
74+
'''
75+
Depending on the hrpsys version, different RTC implementation can be
76+
returned, e.g. for "rmfo", older returns AbsoluteForceSensor while
77+
newer does RemoveForceSensorLinkOffset. So in this testcase we only
78+
check the first element of the returned list (e.g. "rmfo" instead of
79+
its implementation).
80+
'''
81+
self.assertTrue(
82+
self._compare_rtclist(self.robot.getRTCList(), self._RTC_LIST))
6683

67-
def test_getRTCList_customrtcs(self):
84+
def test_getRTCList_customrtcs_args_correct(self):
6885
'''
6986
Test when the RTC list was passed from the client.
7087
@@ -73,9 +90,27 @@ def test_getRTCList_customrtcs(self):
7390
which is not elegant but as of now I can't think of a better way.
7491
'''
7592
self.robot = HIRONX()
76-
self.robot.init(rtcs=self._RTC_LIST_CUSTOM)
93+
# Passing 1st elems from _RTC_LIST_CUSTOM, to init method that calls
94+
# internally getRTCList.
95+
self.robot.init(rtcs='seq, sh, fk')
96+
self.assertTrue(
97+
self._compare_rtclist(
98+
self.robot.getRTCList(), self._RTC_LIST_CUSTOM))
99+
100+
def test_getRTCList_customrtcs_args_wrong(self):
101+
'''
102+
Test when the RTC list was passed from the client, in wrong format.
103+
'''
104+
# Passing the list of RTCs falling short of requirement.
105+
self.assertRaises(
106+
ValueError, self.robot.getRTCList, rtcs_str='seq, sh')
77107

78-
self.assertListEqual(self.robot.getRTCList(), self._RTC_LIST_CUSTOM)
108+
# Passing 1st elems from _RTC_LIST_CUSTOM,
109+
# but list is not the right type of arg.
110+
## http://stackoverflow.com/a/6103930/577001
111+
self.assertRaises(
112+
TypeError, lambda: self.robot.getRTCList,
113+
rtcs_str=['seq', 'sh', 'fk', 'el', 'co', 'log'])
79114

80115
if __name__ == '__main__':
81116
import rostest

0 commit comments

Comments
 (0)