From 40e3ffebd084c82e6ae26207ce181e50a58e068b Mon Sep 17 00:00:00 2001 From: "Isaac I.Y. Saito" <130s@2000.jukuin.keio.ac.jp> Date: Thu, 6 Apr 2017 00:29:04 -0700 Subject: [PATCH 1/4] [ros_bridge][py] Refactoring getRTCList method. `Rtclist` arg wasn't used in `hironx_ros_bridge/hironx_client.py`. Rename it to express its usage is private only and utilize it for future purpose. --- .../src/hironx_ros_bridge/hironx_client.py | 27 +++++---- hironx_ros_bridge/test/test-hironx.test | 3 + hironx_ros_bridge/test/test_hironx_client.py | 58 +++++++++++++++++++ 3 files changed, 74 insertions(+), 14 deletions(-) create mode 100755 hironx_ros_bridge/test/test_hironx_client.py diff --git a/hironx_ros_bridge/src/hironx_ros_bridge/hironx_client.py b/hironx_ros_bridge/src/hironx_ros_bridge/hironx_client.py index 8f9d65a2..a240ec0a 100644 --- a/hironx_ros_bridge/src/hironx_ros_bridge/hironx_client.py +++ b/hironx_ros_bridge/src/hironx_ros_bridge/hironx_client.py @@ -307,7 +307,16 @@ class via the link above; nicely formatted api doc web page HandGroups = {'rhand': [2, 3, 4, 5], 'lhand': [6, 7, 8, 9]} - RtcList = [] + _RTClist = [ + ['seq', "SequencePlayer"], + ['sh', "StateHolder"], + ['fk', "ForwardKinematics"], + ['ic', "ImpedanceController"], + ['el', "SoftErrorLimiter"], + # ['co', "CollisionDetector"], + ['sc', "ServoController"], + ['log', "DataLogger"], + ] # servo controller (grasper) sc = None @@ -442,26 +451,16 @@ def getRTCList(self): @rerutrn List of available components. Each element consists of a list of abbreviated and full names of the component. ''' - rtclist = [ - ['seq', "SequencePlayer"], - ['sh', "StateHolder"], - ['fk', "ForwardKinematics"], - ['ic', "ImpedanceController"], - ['el', "SoftErrorLimiter"], - # ['co', "CollisionDetector"], - ['sc', "ServoController"], - ['log', "DataLogger"], - ] if hasattr(self, 'rmfo'): self.ms.load("RemoveForceSensorLinkOffset") self.ms.load("AbsoluteForceSensor") if "RemoveForceSensorLinkOffset" in self.ms.get_factory_names(): - rtclist.append(['rmfo', "RemoveForceSensorLinkOffset"]) + self._RTClist.append(['rmfo', "RemoveForceSensorLinkOffset"]) elif "AbsoluteForceSensor" in self.ms.get_factory_names(): - rtclist.append(['rmfo', "AbsoluteForceSensor"]) + self._RTClist.append(['rmfo', "AbsoluteForceSensor"]) else: print "Component rmfo is not loadable." - return rtclist + return self._RTClist # hand interface # effort: 1~100[%] diff --git a/hironx_ros_bridge/test/test-hironx.test b/hironx_ros_bridge/test/test-hironx.test index cf3548ea..9a09bf11 100644 --- a/hironx_ros_bridge/test/test-hironx.test +++ b/hironx_ros_bridge/test/test-hironx.test @@ -25,4 +25,7 @@ args="-ORBInitRef NameService=corbaloc:iiop:localhost:2809/NameService" /> + diff --git a/hironx_ros_bridge/test/test_hironx_client.py b/hironx_ros_bridge/test/test_hironx_client.py new file mode 100755 index 00000000..fa37b667 --- /dev/null +++ b/hironx_ros_bridge/test/test_hironx_client.py @@ -0,0 +1,58 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +# Software License Agreement (BSD License) +# +# Copyright (c) 2017, TORK +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following +# disclaimer in the documentation and/or other materials provided +# with the distribution. +# * Neither the name of TORK (Tokyo Opensource Robotics Kyokai Association). +# nor the names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. + +from test_hironx import TestHiro + +PKG = 'hironx_ros_bridge' + + +class TestHiroClient(TestHiro): + + def test_getRTCList(self): + RTC_LIST = [ + ['seq', "SequencePlayer"], + ['sh', "StateHolder"], + ['fk', "ForwardKinematics"], + ['ic', "ImpedanceController"], + ['el', "SoftErrorLimiter"], + # ['co', "CollisionDetector"], + ['sc', "ServoController"], + ['log', "DataLogger"], + ] + self.assertListEqual(self.robot.getRTCList(), RTC_LIST) + +if __name__ == '__main__': + import rostest + rostest.rosrun(PKG, 'test_hronx_client', TestHiroClient) From 0541637350c1b0c3ec9fdef462df9cc4bb290797 Mon Sep 17 00:00:00 2001 From: "Isaac I.Y. Saito" <130s@2000.jukuin.keio.ac.jp> Date: Tue, 25 Apr 2017 15:39:18 -0700 Subject: [PATCH 2/4] [ros_bridge][py] Allow passing RTC list from hironx.py client. --- hironx_ros_bridge/scripts/hironx.py | 15 ++++++++- .../src/hironx_ros_bridge/hironx_client.py | 9 +++++- hironx_ros_bridge/test/test_hironx_client.py | 32 ++++++++++++++++--- 3 files changed, 50 insertions(+), 6 deletions(-) diff --git a/hironx_ros_bridge/scripts/hironx.py b/hironx_ros_bridge/scripts/hironx.py index d2602670..575cea69 100755 --- a/hironx_ros_bridge/scripts/hironx.py +++ b/hironx_ros_bridge/scripts/hironx.py @@ -56,12 +56,23 @@ ' this script, but can use RTM. To use ROS, do not forget' \ ' to run rosbridge. How to do so? --> http://wiki.ros.org/rtmros_nextage/Tutorials/Operating%20Hiro%2C%20NEXTAGE%20OPEN' +RTC_LIST = [ + ['seq', "SequencePlayer"], + ['sh', "StateHolder"], + ['fk', "ForwardKinematics"], + ['ic', "ImpedanceController"], + ['el', "SoftErrorLimiter"], + # ['co', "CollisionDetector"], + ['sc', "ServoController"], + ['log', "DataLogger"],] + if __name__ == '__main__': parser = argparse.ArgumentParser(description='hiro command line interpreters') parser.add_argument('--host', help='corba name server hostname') parser.add_argument('--port', help='corba name server port number') parser.add_argument('--modelfile', help='robot model file nmae') parser.add_argument('--robot', help='robot modlule name (RobotHardware0 for real robot, Robot()') + parser.add_argument('--rtcs', help='RT components to activate. If nothing passed then default value will be used.') args, unknown = parser.parse_known_args() unknown = [u for u in unknown if u[:2] != '__'] # filter out ros arguments @@ -73,13 +84,15 @@ args.robot = "RobotHardware0" if args.host else "HiroNX(Robot)0" if not args.modelfile: args.modelfile = "/opt/jsk/etc/HIRONX/model/main.wrl" if args.host else "" + if not args.rtcs: + args.rtcs = RTC_LIST # support old style format if len(unknown) >= 2: args.robot = unknown[0] args.modelfile = unknown[1] robot = hiro = hironx_client.HIRONX() - robot.init(robotname=args.robot, url=args.modelfile) + robot.init(robotname=args.robot, url=args.modelfile, rtcs=args.rtcs) # ROS Client try: diff --git a/hironx_ros_bridge/src/hironx_ros_bridge/hironx_client.py b/hironx_ros_bridge/src/hironx_ros_bridge/hironx_client.py index a240ec0a..46446d9d 100644 --- a/hironx_ros_bridge/src/hironx_ros_bridge/hironx_client.py +++ b/hironx_ros_bridge/src/hironx_ros_bridge/hironx_client.py @@ -328,7 +328,7 @@ class via the link above; nicely formatted api doc web page "the function call was successful, since not " + "all methods internally called return status") - def init(self, robotname="HiroNX(Robot)0", url=""): + def init(self, robotname="HiroNX(Robot)0", url="", rtcs=_RTClist): ''' Calls init from its superclass, which tries to connect RTCManager, looks for ModelLoader, and starts necessary RTC components. Also runs @@ -337,6 +337,11 @@ def init(self, robotname="HiroNX(Robot)0", url=""): @type robotname: str @type url: str + @type rtcs: [[str, str]] + @param rtcs: List of list of RTC names. Each inner list consists of + 'SHORTENED' name and the 'FULLNAME'. + + example: [['seq', "SequencePlayer"], ['sh', "StateHolder"],,,] ''' # reload for hrpsys 315.1.8 print(self.configurator_name + "waiting ModelLoader") @@ -361,6 +366,8 @@ def init(self, robotname="HiroNX(Robot)0", url=""): # HrpsysConfigurator.init(self, robotname=robotname, url=url) self.sensors = self.getSensors(url) + if rtcs: + self._RTClist = rtcs # all([rtm.findRTC(rn[0], rtm.rootnc) for rn in self.getRTCList()]) # not working somehow... if set([rn[0] for rn in self.getRTCList()]).issubset(set([x.name() for x in self.ms.get_components()])) : print(self.configurator_name + "hrpsys components are already created and running") diff --git a/hironx_ros_bridge/test/test_hironx_client.py b/hironx_ros_bridge/test/test_hironx_client.py index fa37b667..c129c455 100755 --- a/hironx_ros_bridge/test/test_hironx_client.py +++ b/hironx_ros_bridge/test/test_hironx_client.py @@ -33,6 +33,7 @@ # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. +from hironx_ros_bridge.hironx_client import HIRONX from test_hironx import TestHiro PKG = 'hironx_ros_bridge' @@ -40,8 +41,7 @@ class TestHiroClient(TestHiro): - def test_getRTCList(self): - RTC_LIST = [ + _RTC_LIST = [ ['seq', "SequencePlayer"], ['sh', "StateHolder"], ['fk', "ForwardKinematics"], @@ -50,8 +50,32 @@ def test_getRTCList(self): # ['co', "CollisionDetector"], ['sc', "ServoController"], ['log', "DataLogger"], - ] - self.assertListEqual(self.robot.getRTCList(), RTC_LIST) + ] + + _RTC_LIST_CUSTOM = [ + ['seq', "SequencePlayer"], + ['sh', "StateHolder"], + ['fk', "ForwardKinematics"], + ['el', "SoftErrorLimiter"], + ['co', "CollisionDetector"], + ['log', "DataLogger"], + ] + + def test_getRTCList(self): + self.assertListEqual(self.robot.getRTCList(), self._RTC_LIST) + + def test_getRTCList_customrtcs(self): + ''' + Test when the RTC list was passed from the client. + + Because this uses HIRONX.init(), which is already done in the + superclass, HIRONX class instance is re-generated within this method, + which is not elegant but as of now I can't think of a better way. + ''' + self.robot = HIRONX() + self.robot.init(rtcs=self._RTC_LIST_CUSTOM) + + self.assertListEqual(self.robot.getRTCList(), self._RTC_LIST_CUSTOM) if __name__ == '__main__': import rostest From 94196e714a1e1546ffe27bccbf416d64c034fa81 Mon Sep 17 00:00:00 2001 From: "Isaac I.Y. Saito" <130s@2000.jukuin.keio.ac.jp> Date: Tue, 25 Apr 2017 17:48:47 -0700 Subject: [PATCH 3/4] [ros_bridge] getRTCList to accept custom list of RTCs. This allows the downstream `nextage_ros_bridge` to add a patch to fix https://github.com/tork-a/rtmros_nextage/issues/308. [ros_bridge][py][test] Export a testcase module that can be re-used. --- hironx_ros_bridge/scripts/hironx.py | 13 +--- .../src/hironx_ros_bridge/hironx_client.py | 77 +++++++++++++++---- .../testutil}/test_hironx_client.py | 52 +++++++++++-- 3 files changed, 109 insertions(+), 33 deletions(-) rename hironx_ros_bridge/{test => src/hironx_ros_bridge/testutil}/test_hironx_client.py (58%) diff --git a/hironx_ros_bridge/scripts/hironx.py b/hironx_ros_bridge/scripts/hironx.py index 575cea69..a91bf70f 100755 --- a/hironx_ros_bridge/scripts/hironx.py +++ b/hironx_ros_bridge/scripts/hironx.py @@ -56,15 +56,8 @@ ' this script, but can use RTM. To use ROS, do not forget' \ ' to run rosbridge. How to do so? --> http://wiki.ros.org/rtmros_nextage/Tutorials/Operating%20Hiro%2C%20NEXTAGE%20OPEN' -RTC_LIST = [ - ['seq', "SequencePlayer"], - ['sh', "StateHolder"], - ['fk', "ForwardKinematics"], - ['ic', "ImpedanceController"], - ['el', "SoftErrorLimiter"], - # ['co', "CollisionDetector"], - ['sc', "ServoController"], - ['log', "DataLogger"],] +# The default RTCs for Hironx +RTC_LIST = 'seq, sh, fk, ic, el, sc, log' if __name__ == '__main__': parser = argparse.ArgumentParser(description='hiro command line interpreters') @@ -72,7 +65,7 @@ parser.add_argument('--port', help='corba name server port number') parser.add_argument('--modelfile', help='robot model file nmae') parser.add_argument('--robot', help='robot modlule name (RobotHardware0 for real robot, Robot()') - parser.add_argument('--rtcs', help='RT components to activate. If nothing passed then default value will be used.') + parser.add_argument('--rtcs', help="RT components to activate. If nothing passed then default value will be used. Example: '{}'".format(RTC_LIST)) args, unknown = parser.parse_known_args() unknown = [u for u in unknown if u[:2] != '__'] # filter out ros arguments diff --git a/hironx_ros_bridge/src/hironx_ros_bridge/hironx_client.py b/hironx_ros_bridge/src/hironx_ros_bridge/hironx_client.py index 46446d9d..33edfe2d 100644 --- a/hironx_ros_bridge/src/hironx_ros_bridge/hironx_client.py +++ b/hironx_ros_bridge/src/hironx_ros_bridge/hironx_client.py @@ -307,7 +307,10 @@ class via the link above; nicely formatted api doc web page HandGroups = {'rhand': [2, 3, 4, 5], 'lhand': [6, 7, 8, 9]} - _RTClist = [ + # This shouldn't be accessed once turned to True during `init` method. + is_rtc_activated = False + + _RTC_list = [ ['seq', "SequencePlayer"], ['sh', "StateHolder"], ['fk', "ForwardKinematics"], @@ -318,6 +321,9 @@ class via the link above; nicely formatted api doc web page ['log', "DataLogger"], ] + # List of the name of RT Components that hrpsys requires at minimum. + _RTC_NAME_MINREQ = ['seq', 'sh', 'fk'] + # servo controller (grasper) sc = None sc_svc = None @@ -328,7 +334,7 @@ class via the link above; nicely formatted api doc web page "the function call was successful, since not " + "all methods internally called return status") - def init(self, robotname="HiroNX(Robot)0", url="", rtcs=_RTClist): + def init(self, robotname="HiroNX(Robot)0", url="", rtcs=None): ''' Calls init from its superclass, which tries to connect RTCManager, looks for ModelLoader, and starts necessary RTC components. Also runs @@ -337,11 +343,10 @@ def init(self, robotname="HiroNX(Robot)0", url="", rtcs=_RTClist): @type robotname: str @type url: str - @type rtcs: [[str, str]] - @param rtcs: List of list of RTC names. Each inner list consists of - 'SHORTENED' name and the 'FULLNAME'. + @type rtcs: [str] + @param rtcs: List of abbreviated RTC names. - example: [['seq', "SequencePlayer"], ['sh', "StateHolder"],,,] + example: ['seq', 'sh',,,] ''' # reload for hrpsys 315.1.8 print(self.configurator_name + "waiting ModelLoader") @@ -366,10 +371,8 @@ def init(self, robotname="HiroNX(Robot)0", url="", rtcs=_RTClist): # HrpsysConfigurator.init(self, robotname=robotname, url=url) self.sensors = self.getSensors(url) - if rtcs: - self._RTClist = rtcs # all([rtm.findRTC(rn[0], rtm.rootnc) for rn in self.getRTCList()]) # not working somehow... - if set([rn[0] for rn in self.getRTCList()]).issubset(set([x.name() for x in self.ms.get_components()])) : + if set([rn[0] for rn in self.getRTCList(rtcs)]).issubset(set([x.name() for x in self.ms.get_components()])) : print(self.configurator_name + "hrpsys components are already created and running") self.findComps(max_timeout_count=0, verbose=True) else: @@ -450,24 +453,68 @@ def goInitial(self, tm=7, wait=True, init_pose_type=0): self.seq_svc.waitInterpolationOfGroup(self.Groups[i][0]) return ret - def getRTCList(self): + def getRTCList(self, rtcs_str=None): ''' + @summary: Return the list of activated RT components. As opposed to + its naming, this also: + 1) activate an rmfo (stands for "remove force offset") + RTC. + 2) selectively activate RTCs passed by rtcs_str. This is + possible ONLY during the initialization process done + by `init` method. @see: HrpsysConfigurator.getRTCList + @type rtcs_str: str + @param rtcs_str: A single str for a set of abbreviated names of RTCs, + each of which is comma-separated. This is possible + ONLY during the initialization process done by + `init` method. + example: "seq, sh, fk, ic, el, sc, log" @rtype [[str]] - @rerutrn List of available components. Each element consists of a list + @return List of available components. Each element consists of a list of abbreviated and full names of the component. + @raise TypeError: When rtcs_str isn't a string. + @raise ValueError: When rtcs_str does not contain minimum + required RTCs. ''' - if hasattr(self, 'rmfo'): + if rtcs_str: + if self.is_rtc_activated: + print('RTCs are already activated. Skipping the passed request: {}'.format(rtcs_str)) + else: + if not isinstance(rtcs_str, basestring): + raise TypeError('rtcs_str needs to be string.') + # Set a new list of RTCs + new_rtcs = [] + # Separate by comma and remove whitespace. + rtcs_req_list = [x.strip() for x in rtcs_str.split(",")] + # Check if minimum required RTCs are passed. + if not all(x in rtcs_req_list for x in self._RTC_NAME_MINREQ): + raise ValueError('{} are required at minimum'.format( + self._RTC_NAME_MINREQ)) + for rtc_requested in rtcs_req_list: + for elem in self._RTC_list: + if elem[0] == rtc_requested: + new_rtcs.append(elem) + break + self._RTC_list = new_rtcs + self.is_rtc_activated = True + + is_rmfo_initiated = False + # For some reason using built-in "any" method yields + # `TypeError: 'module' object is not callable`, so do the iteration. + for rtc_list in self._RTC_list: + if 'rmfo' in rtc_list: + is_rmfo_initiated = True + if hasattr(self, 'rmfo') and not is_rmfo_initiated: self.ms.load("RemoveForceSensorLinkOffset") self.ms.load("AbsoluteForceSensor") if "RemoveForceSensorLinkOffset" in self.ms.get_factory_names(): - self._RTClist.append(['rmfo', "RemoveForceSensorLinkOffset"]) + self._RTC_list.append(['rmfo', "RemoveForceSensorLinkOffset"]) elif "AbsoluteForceSensor" in self.ms.get_factory_names(): - self._RTClist.append(['rmfo', "AbsoluteForceSensor"]) + self._RTC_list.append(['rmfo', "AbsoluteForceSensor"]) else: print "Component rmfo is not loadable." - return self._RTClist + return self._RTC_list # hand interface # effort: 1~100[%] diff --git a/hironx_ros_bridge/test/test_hironx_client.py b/hironx_ros_bridge/src/hironx_ros_bridge/testutil/test_hironx_client.py similarity index 58% rename from hironx_ros_bridge/test/test_hironx_client.py rename to hironx_ros_bridge/src/hironx_ros_bridge/testutil/test_hironx_client.py index c129c455..0106957e 100755 --- a/hironx_ros_bridge/test/test_hironx_client.py +++ b/hironx_ros_bridge/src/hironx_ros_bridge/testutil/test_hironx_client.py @@ -47,24 +47,42 @@ class TestHiroClient(TestHiro): ['fk', "ForwardKinematics"], ['ic', "ImpedanceController"], ['el', "SoftErrorLimiter"], - # ['co', "CollisionDetector"], ['sc', "ServoController"], ['log', "DataLogger"], + # rmfo will be automatically added in getRTCList. + ['rmfo', 'RemoveForceSensorLinkOffset'] ] _RTC_LIST_CUSTOM = [ ['seq', "SequencePlayer"], ['sh', "StateHolder"], ['fk', "ForwardKinematics"], - ['el', "SoftErrorLimiter"], - ['co', "CollisionDetector"], - ['log', "DataLogger"], + ['rmfo', 'RemoveForceSensorLinkOffset'] ] + def _compare_2dlist(self, twodim_list_a, twodim_list_b): + ''' + Compare the first element in all elements of the 2nd list. + E.g. For [['a0', 'a1'], ['b0', 'b1'],..., ['n0', 'n1']], this method + checks a0, b0, n0 + @rtype bool + ''' + return set([a[0] for a in twodim_list_a]) == set( + [b[0] for b in twodim_list_b]) + def test_getRTCList(self): - self.assertListEqual(self.robot.getRTCList(), self._RTC_LIST) + ''' + Depending on the hrpsys version, different RTC implementation can be + returned, e.g. for "rmfo", older returns AbsoluteForceSensor while + newer does RemoveForceSensorLinkOffset. So in this testcase we only + check the first element of the returned list (e.g. "rmfo" instead of + its implementation). + ''' + self.assertTrue( + self._compare_2dlist( + self.robot.getRTCList(), self._RTC_LIST)) - def test_getRTCList_customrtcs(self): + def test_getRTCList_customrtcs_args_correct(self): ''' Test when the RTC list was passed from the client. @@ -73,9 +91,27 @@ def test_getRTCList_customrtcs(self): which is not elegant but as of now I can't think of a better way. ''' self.robot = HIRONX() - self.robot.init(rtcs=self._RTC_LIST_CUSTOM) + # Passing 1st elems from _RTC_LIST_CUSTOM, to init method that calls + # internally getRTCList. + self.robot.init(rtcs='seq, sh, fk') + self.assertTrue( + self._compare_2dlist( + self.robot.getRTCList(), self._RTC_LIST_CUSTOM)) + + def test_getRTCList_customrtcs_args_wrong(self): + ''' + Test when the RTC list was passed from the client, in wrong format. + ''' + # Passing the list of RTCs falling short of requirement. + self.assertRaises( + ValueError, self.robot.getRTCList, rtcs_str='seq, sh') - self.assertListEqual(self.robot.getRTCList(), self._RTC_LIST_CUSTOM) + # Passing 1st elems from _RTC_LIST_CUSTOM, + # but list is not the right type of arg. + ## http://stackoverflow.com/a/6103930/577001 + self.assertRaises( + TypeError, lambda: self.robot.getRTCList, + rtcs_str=['seq', 'sh', 'fk', 'el', 'co', 'log']) if __name__ == '__main__': import rostest From c1b90d7a0e16ac94715a3c3a4e812c14489f7764 Mon Sep 17 00:00:00 2001 From: "Isaac I.Y. Saito" <130s@2000.jukuin.keio.ac.jp> Date: Fri, 28 Apr 2017 21:56:37 -0700 Subject: [PATCH 4/4] [ros_bridge][py] Add back CollisionDetector as an option. Now that RTCs to activate is selectable from the end client (e.g. hironx.py), we need to expose all RTCs available. [ros_bridge][test][py] Refactoring. --- .../src/hironx_ros_bridge/hironx_client.py | 19 +++++++++++++++++-- .../testutil => test}/test_hironx_client.py | 16 +++------------- 2 files changed, 20 insertions(+), 15 deletions(-) rename hironx_ros_bridge/{src/hironx_ros_bridge/testutil => test}/test_hironx_client.py (89%) diff --git a/hironx_ros_bridge/src/hironx_ros_bridge/hironx_client.py b/hironx_ros_bridge/src/hironx_ros_bridge/hironx_client.py index 33edfe2d..70d645b5 100644 --- a/hironx_ros_bridge/src/hironx_ros_bridge/hironx_client.py +++ b/hironx_ros_bridge/src/hironx_ros_bridge/hironx_client.py @@ -310,13 +310,25 @@ class via the link above; nicely formatted api doc web page # This shouldn't be accessed once turned to True during `init` method. is_rtc_activated = False + # Default set of RTCs to be activated. _RTC_list = [ ['seq', "SequencePlayer"], ['sh', "StateHolder"], ['fk', "ForwardKinematics"], ['ic', "ImpedanceController"], ['el', "SoftErrorLimiter"], - # ['co', "CollisionDetector"], + ['sc', "ServoController"], + ['log', "DataLogger"], + ] + + # All available RTCs. This list is meant to be immutable. + RTCs_all_available = [ + ['seq', "SequencePlayer"], + ['sh', "StateHolder"], + ['fk', "ForwardKinematics"], + ['ic', "ImpedanceController"], + ['el', "SoftErrorLimiter"], + ['co', "CollisionDetector"], ['sc', "ServoController"], ['log', "DataLogger"], ] @@ -491,8 +503,11 @@ def getRTCList(self, rtcs_str=None): if not all(x in rtcs_req_list for x in self._RTC_NAME_MINREQ): raise ValueError('{} are required at minimum'.format( self._RTC_NAME_MINREQ)) + + # Create a new list of requested RTC with the name of + # implementations. for rtc_requested in rtcs_req_list: - for elem in self._RTC_list: + for elem in self.RTCs_all_available: if elem[0] == rtc_requested: new_rtcs.append(elem) break diff --git a/hironx_ros_bridge/src/hironx_ros_bridge/testutil/test_hironx_client.py b/hironx_ros_bridge/test/test_hironx_client.py similarity index 89% rename from hironx_ros_bridge/src/hironx_ros_bridge/testutil/test_hironx_client.py rename to hironx_ros_bridge/test/test_hironx_client.py index 0106957e..49c923ab 100755 --- a/hironx_ros_bridge/src/hironx_ros_bridge/testutil/test_hironx_client.py +++ b/hironx_ros_bridge/test/test_hironx_client.py @@ -41,18 +41,6 @@ class TestHiroClient(TestHiro): - _RTC_LIST = [ - ['seq', "SequencePlayer"], - ['sh', "StateHolder"], - ['fk', "ForwardKinematics"], - ['ic', "ImpedanceController"], - ['el', "SoftErrorLimiter"], - ['sc', "ServoController"], - ['log', "DataLogger"], - # rmfo will be automatically added in getRTCList. - ['rmfo', 'RemoveForceSensorLinkOffset'] - ] - _RTC_LIST_CUSTOM = [ ['seq', "SequencePlayer"], ['sh', "StateHolder"], @@ -80,7 +68,9 @@ def test_getRTCList(self): ''' self.assertTrue( self._compare_2dlist( - self.robot.getRTCList(), self._RTC_LIST)) + self.robot.getRTCList(), + # Accessing a private member var only for testing purpose. + self.robot._RTC_list)) def test_getRTCList_customrtcs_args_correct(self): '''