Skip to content

Commit 62fca02

Browse files
committed
Merge pull request #189 from personalrobotics/block_sorting
Changes for the block sorting demo.
2 parents b08ee7e + a6f4284 commit 62fca02

File tree

12 files changed

+672
-6
lines changed

12 files changed

+672
-6
lines changed

src/prpy/base/barretthand.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -239,8 +239,6 @@ def TareForceTorqueSensor(hand):
239239
"""
240240
if not hand.ft_simulated:
241241
hand.ft_sensor.SendCommand('Tare')
242-
# TODO: Do we still need to wait this long?
243-
time.sleep(2)
244242

245243
def _GetJointFromName(self, name):
246244
robot = self.manipulator.GetRobot()

src/prpy/base/robot.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,8 @@ def __dir__(self):
8888
method_names.update(self.planner.get_planning_method_names())
8989
if hasattr(self, 'actions') and self.actions is not None:
9090
method_names.update(self.actions.get_actions())
91+
if hasattr(self, 'detector') and self.detector is not None:
92+
method_names.update(self.detector.get_perception_method_names())
9193

9294
return list(method_names)
9395

@@ -113,6 +115,14 @@ def wrapper_method(*args, **kw_args):
113115
def wrapper_method(*args, **kw_args):
114116
return delegate_method(self, *args, **kw_args)
115117
return wrapper_method
118+
elif (hasattr(self, 'detector') and self.detector is not None
119+
and self.detector.has_perception_method(name)):
120+
121+
delegate_method = getattr(self.detector, name)
122+
@functools.wraps(delegate_method)
123+
def wrapper_method(*args, **kw_args):
124+
return delegate_method(self, *args, **kw_args)
125+
return wrapper_method
116126

117127
raise AttributeError('{0:s} is missing method "{1:s}".'.format(repr(self), name))
118128

src/prpy/base/wam.py

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,7 @@ def ServoTo(manipulator, target, duration, timeStep=0.05, collisionChecking=True
157157

158158
if not inCollision:
159159
for i in range(1,steps):
160+
import time
160161
manipulator.Servo(velocities)
161162
time.sleep(timeStep)
162163
manipulator.Servo([0] * len(manipulator.GetArmIndices()))
@@ -223,7 +224,8 @@ def ClearTrajectoryStatus(manipulator):
223224
manipulator.controller.SendCommand('ClearStatus')
224225

225226
def MoveUntilTouch(manipulator, direction, distance, max_distance=None,
226-
max_force=5.0, max_torque=None, ignore_collisions=None, **kw_args):
227+
max_force=5.0, max_torque=None, ignore_collisions=None,
228+
velocity_limit_scale=0.25, **kw_args):
227229
"""Execute a straight move-until-touch action.
228230
This action stops when a sufficient force is is felt or the manipulator
229231
moves the maximum distance. The motion is considered successful if the
@@ -235,7 +237,10 @@ def MoveUntilTouch(manipulator, direction, distance, max_distance=None,
235237
@param max_distance maximum distance in meters
236238
@param max_force maximum force in Newtons
237239
@param max_torque maximum torque in Newton-Meters
238-
@param ignore_collisions collisions with these objects are ignored when planning the path, e.g. the object you think you will touch
240+
@param ignore_collisions collisions with these objects are ignored when
241+
planning the path, e.g. the object you think you will touch
242+
@param velocity_limit_scale A multiplier to use to scale velocity limits
243+
when executing MoveUntilTouch ( < 1 in most cases).
239244
@param **kw_args planner parameters
240245
@return felt_force flag indicating whether we felt a force.
241246
"""
@@ -299,7 +304,10 @@ def MoveUntilTouch(manipulator, direction, distance, max_distance=None,
299304
manipulator.hand.TareForceTorqueSensor()
300305

301306
try:
302-
robot.ExecutePath(path)
307+
with robot.CreateRobotStateSaver(Robot.SaveParameters.JointMaxVelocityAndAcceleration):
308+
vl = robot.GetDOFVelocityLimits()
309+
manipulator.SetVelocityLimits(velocity_limit_scale*vl, 0.5)
310+
robot.ExecutePath(path)
303311
return False
304312
except exceptions.TrajectoryAborted as e:
305313
logger.warn('MoveUntilTouch aborted: %s', str(e))

src/prpy/perception/__init__.py

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
#!/usr/bin/env python
2+
3+
# Copyright (c) 2015, Carnegie Mellon University
4+
# All rights reserved.
5+
# Authors: Jennifer King <jeking@cs.cmu.edu>
6+
#
7+
# Redistribution and use in source and binary forms, with or without
8+
# modification, are permitted provided that the following conditions are met:
9+
#
10+
# - Redistributions of source code must retain the above copyright notice, this
11+
# list of conditions and the following disclaimer.
12+
# - Redistributions in binary form must reproduce the above copyright notice,
13+
# this list of conditions and the following disclaimer in the documentation
14+
# and/or other materials provided with the distribution.
15+
# - Neither the name of Carnegie Mellon University nor the names of its
16+
# contributors may be used to endorse or promote products derived from this
17+
# software without specific prior written permission.
18+
#
19+
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20+
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21+
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22+
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
23+
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24+
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25+
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26+
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27+
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28+
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29+
# POSSIBILITY OF SUCH DAMAGE.
30+
31+
from base import PerceptionModule, PerceptionMethod
32+
from apriltags import ApriltagsModule
33+
from simulated import SimulatedPerceptionModule
34+
from rock_module import RockModule

src/prpy/perception/apriltags.py

Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
#!/usr/bin/env python
2+
3+
# Copyright (c) 2015, Carnegie Mellon University
4+
# All rights reserved.
5+
# Authors: Jennifer King <jeking@cs.cmu.edu>
6+
#
7+
# Redistribution and use in source and binary forms, with or without
8+
# modification, are permitted provided that the following conditions are met:
9+
#
10+
# - Redistributions of source code must retain the above copyright notice, this
11+
# list of conditions and the following disclaimer.
12+
# - Redistributions in binary form must reproduce the above copyright notice,
13+
# this list of conditions and the following disclaimer in the documentation
14+
# and/or other materials provided with the distribution.
15+
# - Neither the name of Carnegie Mellon University nor the names of its
16+
# contributors may be used to endorse or promote products derived from this
17+
# software without specific prior written permission.
18+
#
19+
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20+
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21+
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22+
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
23+
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24+
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25+
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26+
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27+
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28+
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29+
# POSSIBILITY OF SUCH DAMAGE.
30+
31+
import logging
32+
from base import PerceptionModule, PerceptionMethod
33+
34+
logger = logging.getLogger(__name__)
35+
logger.setLevel(logging.INFO)
36+
37+
class ApriltagsModule(PerceptionModule):
38+
39+
def __init__(self, marker_topic, marker_data_path, kinbody_path,
40+
detection_frame, destination_frame):
41+
"""
42+
This initializes an April Tags detector.
43+
44+
@param marker_topic The ROS topic to read markers from. Typically the output topic for April Tags
45+
@param marker_data_path The json file where the association between tag and object is stored
46+
@param kinbody_path The path to the folder where kinbodies are stored
47+
@param detection_frame The TF frame of the camera
48+
@param destination_frame The desired world TF frame
49+
"""
50+
51+
super(ApriltagsModule, self).__init__()
52+
53+
self.marker_topic = marker_topic
54+
self.marker_data_path = marker_data_path
55+
self.kinbody_path = kinbody_path
56+
self.detection_frame = detection_frame
57+
self.destination_frame = destination_frame
58+
59+
60+
def __str__(self):
61+
return self.__class__.__name__
62+
63+
def DetectObjects(self, env, object_names, **kw_args):
64+
"""
65+
This hack detects only the objects in object_names. Updates existing
66+
objects, but only adds objects in the object_names list.
67+
68+
@param env: The current OpenRAVE environment
69+
@param object_names: The list of names of objects to detect
70+
"""
71+
added_kinbodies, updated_kinbodies = self._DetectObjects(env, **kw_args);
72+
detected = [];
73+
for body in added_kinbodies:
74+
if not (body.GetName() in object_names):
75+
env.RemoveKinbody(body);
76+
else:
77+
detected.append(body);
78+
return detected;
79+
80+
def DetectObject(self, env, object_name, **kw_args):
81+
"""
82+
Detects a single named object.
83+
"""
84+
return (self._DetectObjects( env, object_names=[object_name], **kw_args))[0][0];
85+
86+
87+
def _DetectObjects(self, env, marker_topic, marker_data_path, kinbody_path,
88+
detection_frame, destination_frame,**kw_args):
89+
"""
90+
Use the apriltags service to detect objects and add them to the
91+
environment. Params are as in __init__.
92+
93+
@param env: The current OpenRAVE environment
94+
@param marker_topic The ROS topic to read markers from. Typically the output topic for April Tags
95+
@param marker_data_path The json file where the association between tag and object is stored
96+
@param kinbody_path The path to the folder where kinbodies are stored
97+
@param detection_frame The TF frame of the camera
98+
@param destination_frame The desired world TF frame
99+
100+
@return The list of kinbodies associated with the detected apriltags
101+
"""
102+
try:
103+
# Allow caller to override any of the initial parameters
104+
# loaded into the module
105+
if marker_topic is None:
106+
marker_topic = self.marker_topic
107+
108+
if marker_data_path is None:
109+
marker_data_path = self.marker_data_path
110+
111+
if kinbody_path is None:
112+
kinbody_path = self.kinbody_path
113+
114+
115+
if detection_frame is None:
116+
detection_frame = self.detection_frame
117+
118+
if destination_frame is None:
119+
destination_frame = self.destination_frame
120+
121+
# TODO: Creating detector is not instant...might want
122+
# to just do this once in the constructor
123+
import kinbody_detector.kinbody_detector as kd
124+
detector = kd.KinBodyDetector(env,
125+
marker_data_path,
126+
kinbody_path,
127+
marker_topic,
128+
detection_frame,
129+
destination_frame)
130+
131+
logger.warn('Waiting to detect objects...')
132+
return detector.Update()
133+
except Exception, e:
134+
logger.error('Detecton failed update: %s' % str(e))
135+
raise
136+
137+
@PerceptionMethod
138+
def DetectObjects(self, robot, **kw_args):
139+
"""
140+
Overriden method for detection_frame
141+
"""
142+
return self._DetectObjects(robot.GetEnv(),**kwargs)
143+

src/prpy/perception/base.py

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
#!/usr/bin/env python
2+
3+
import functools
4+
5+
class PerceptionMethod(object):
6+
7+
def __init__(self, func):
8+
self.func = func
9+
10+
def __call__(self, instance, robot, *args, **kw_args):
11+
return self.func(instance, robot, *args, **kw_args)
12+
13+
def __get__(self, instance, instancetype):
14+
# Bind the self reference and use update_wrapper to propagate the
15+
# function's metadata (e.g. name and docstring).
16+
wrapper = functools.partial(self.__call__, instance)
17+
functools.update_wrapper(wrapper, self.func)
18+
wrapper.is_perception_method = True
19+
return wrapper
20+
21+
class PerceptionModule(object):
22+
def has_perception_method(self, method_name):
23+
"""
24+
Check if this module has the desired PerceptionMethod
25+
"""
26+
if hasattr(self, method_name):
27+
method = getattr(self, method_name)
28+
if hasattr(method, 'is_perception_method'):
29+
return method.is_perception_method
30+
else:
31+
return False
32+
else:
33+
return False
34+
35+
def get_perception_method_names(self):
36+
"""
37+
@return A list of all the PerceptionMethod functions
38+
defined for this module
39+
"""
40+
return filter(lambda method_name: self.has_perception_method(method_name), dir(self))
41+

0 commit comments

Comments
 (0)