Skip to content

Commit ec8d67c

Browse files
committed
feat: manipulation demo improvements
1 parent 1bccde7 commit ec8d67c

File tree

4 files changed

+115
-21
lines changed

4 files changed

+115
-21
lines changed

examples/manipulation-demo.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
from rai.agents.langchain.core import create_conversational_agent
2525
from rai.communication.ros2 import wait_for_ros2_services, wait_for_ros2_topics
2626
from rai.communication.ros2.connectors import ROS2Connector
27-
from rai.tools.ros2.manipulation import GetObjectPositionsTool, MoveToPointTool
27+
from rai.tools.ros2.manipulation import GetObjectPositionsTool, MoveToPointTool, ResetArmTool
2828
from rai.tools.ros2.simple import GetROS2ImageConfiguredTool
2929
from rai_open_set_vision.tools import GetGrabbingPointTool
3030

@@ -35,7 +35,7 @@
3535

3636
def create_agent():
3737
rclpy.init()
38-
connector = ROS2Connector()
38+
connector = ROS2Connector(executor_type='single_threaded')
3939

4040
required_services = ["/grounded_sam_segment", "/grounding_dino_classify"]
4141
required_topics = ["/color_image5", "/depth_image5", "/color_camera_info5"]
@@ -56,6 +56,7 @@ def create_agent():
5656
get_grabbing_point_tool=GetGrabbingPointTool(connector=connector),
5757
),
5858
MoveToPointTool(connector=connector, manipulator_frame="panda_link0"),
59+
ResetArmTool(connector=connector, manipulator_frame="panda_link0"),
5960
GetROS2ImageConfiguredTool(connector=connector, topic="/color_image5"),
6061
]
6162

src/rai_core/rai/tools/ros2/manipulation/__init__.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,11 @@
1919
"This is a ROS2 feature. Make sure ROS2 is installed and sourced."
2020
)
2121

22-
from .custom import GetObjectPositionsTool, MoveToPointTool, MoveToPointToolInput
22+
from .custom import GetObjectPositionsTool, MoveToPointTool, MoveToPointToolInput, ResetArmTool
2323

2424
__all__ = [
2525
"GetObjectPositionsTool",
2626
"MoveToPointTool",
2727
"MoveToPointToolInput",
28+
"ResetArmTool",
2829
]

src/rai_core/rai/tools/ros2/manipulation/custom.py

Lines changed: 109 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -42,26 +42,28 @@ class MoveToPointToolInput(BaseModel):
4242
x: float = Field(description="The x coordinate of the point to move to")
4343
y: float = Field(description="The y coordinate of the point to move to")
4444
z: float = Field(description="The z coordinate of the point to move to")
45-
task: Literal["grab", "drop"] = Field(
46-
description="Specify the intended action: use 'grab' to pick up an object, or 'drop' to release it. "
47-
"This determines the gripper's behavior during the movement."
48-
)
45+
x1: float = Field(description="The x coordinate of the point to move to")
46+
y1: float = Field(description="The y coordinate of the point to move to")
47+
z1: float = Field(description="The z coordinate of the point to move to")
48+
#task: Literal["grab", "drop"] = Field(
49+
# description="Specify the intended action: use 'grab' to pick up an object, or 'drop' to release it. "
50+
# "This determines the gripper's behavior during the movement."
51+
#)
4952

5053

5154
class MoveToPointTool(BaseROS2Tool):
5255
name: str = "move_to_point"
5356
description: str = (
54-
"Guide the robot's end effector to a specific point within the manipulator's operational space. "
55-
"This tool ensures precise movement to the desired location. "
56-
"While it confirms successful positioning, please note that it doesn't provide feedback on the "
57-
"success of grabbing or releasing objects. Use additional sensors or tools for that information."
57+
"Move an object from one point to another. "
58+
"The tool will move the object to the first point and then to the second point. "
59+
"The tool will not confirm the success of grabbing or releasing objects. Use additional sensors (e.g. camera) or tools for that information."
5860
)
5961

6062
manipulator_frame: str = Field(..., description="Manipulator frame")
6163
min_z: float = Field(default=0.135, description="Minimum z coordinate [m]")
6264
calibration_x: float = Field(default=0.0, description="Calibration x [m]")
6365
calibration_y: float = Field(default=0.0, description="Calibration y [m]")
64-
calibration_z: float = Field(default=0.0, description="Calibration z [m]")
66+
calibration_z: float = Field(default=0.1, description="Calibration z [m]")
6567
additional_height: float = Field(
6668
default=0.05, description="Additional height for the place task [m]"
6769
)
@@ -79,7 +81,10 @@ def _run(
7981
x: float,
8082
y: float,
8183
z: float,
82-
task: Literal["grab", "drop"],
84+
x1: float,
85+
y1: float,
86+
z1: float,
87+
#task: Literal["grab", "drop"],
8388
) -> str:
8489
client = self.connector.node.create_client(
8590
ManipulatorMoveTo,
@@ -92,8 +97,14 @@ def _run(
9297
orientation=self.quaternion,
9398
)
9499

95-
if task == "drop":
96-
pose_stamped.pose.position.z += self.additional_height
100+
pose_stamped1 = PoseStamped()
101+
pose_stamped1.header.frame_id = self.manipulator_frame
102+
pose_stamped1.pose = Pose(
103+
position=Point(x=x1, y=y1, z=z1),
104+
orientation=self.quaternion,
105+
)
106+
#if task == "drop":
107+
# pose_stamped.pose.position.z += self.additional_height
97108

98109
pose_stamped.pose.position.x += self.calibration_x
99110
pose_stamped.pose.position.y += self.calibration_y
@@ -103,21 +114,50 @@ def _run(
103114
[pose_stamped.pose.position.z, self.min_z]
104115
)
105116

117+
pose_stamped1.pose.position.x += self.calibration_x
118+
pose_stamped1.pose.position.y += self.calibration_y
119+
pose_stamped1.pose.position.z += self.calibration_z
120+
121+
pose_stamped1.pose.position.z = np.max(
122+
[pose_stamped1.pose.position.z, self.min_z]
123+
)
124+
125+
106126
request = ManipulatorMoveTo.Request()
107127
request.target_pose = pose_stamped
108128

109-
if task == "grab":
110-
request.initial_gripper_state = True # open
111-
request.final_gripper_state = False # closed
129+
request.initial_gripper_state = True # open
130+
request.final_gripper_state = False # closed
131+
132+
future = client.call_async(request)
133+
self.connector.node.get_logger().debug(
134+
f"Calling ManipulatorMoveTo service with request: x={request.target_pose.pose.position.x:.2f}, y={request.target_pose.pose.position.y:.2f}, z={request.target_pose.pose.position.z:.2f}"
135+
)
136+
response = get_future_result(future, timeout_sec=5.0)
137+
138+
if response is None:
139+
return f"Service call failed for point ({x:.2f}, {y:.2f}, {z:.2f})."
140+
141+
if response.success:
142+
self.connector.logger.info(f"End effector successfully positioned at coordinates ({x:.2f}, {y:.2f}, {z:.2f}).")
112143
else:
113-
request.initial_gripper_state = False # closed
114-
request.final_gripper_state = True # open
144+
self.connector.logger.error(f"Failed to position end effector at coordinates ({x:.2f}, {y:.2f}, {z:.2f}).")
145+
return "Failed to position end effector at coordinates ({x:.2f}, {y:.2f}, {z:.2f})."
146+
147+
request = ManipulatorMoveTo.Request()
148+
request.target_pose = pose_stamped1
149+
150+
request.initial_gripper_state = False # closed
151+
request.final_gripper_state = True # open
152+
115153

116154
future = client.call_async(request)
117155
self.connector.node.get_logger().debug(
118156
f"Calling ManipulatorMoveTo service with request: x={request.target_pose.pose.position.x:.2f}, y={request.target_pose.pose.position.y:.2f}, z={request.target_pose.pose.position.z:.2f}"
119157
)
120158
response = get_future_result(future, timeout_sec=5.0)
159+
160+
121161
if response is None:
122162
return f"Service call failed for point ({x:.2f}, {y:.2f}, {z:.2f})."
123163

@@ -182,3 +222,55 @@ def _run(self, object_name: str):
182222
return f"No {object_name}s detected."
183223
else:
184224
return f"Centroids of detected {object_name}s in {self.target_frame} frame: [{', '.join(map(self.format_pose, mani_frame_poses))}]. Sizes of the detected objects are unknown."
225+
226+
class ResetArmToolInput(BaseModel):
227+
pass
228+
229+
class ResetArmTool(BaseROS2Tool):
230+
name: str = "reset_arm"
231+
description: str = "Reset the arm to the initial position. Use when the arm is stuck or when arm obstructs the objects."
232+
233+
args_schema: Type[ResetArmToolInput] = ResetArmToolInput
234+
235+
# constant quaternion
236+
quaternion: Quaternion = Field(
237+
default=Quaternion(x=0.9238795325112867, y=-0.3826834323650898, z=0.0, w=0.0),
238+
description="Constant quaternion",
239+
)
240+
manipulator_frame: str = Field(..., description="Manipulator frame")
241+
242+
def _run(self):
243+
client = self.connector.node.create_client(
244+
ManipulatorMoveTo,
245+
"/manipulator_move_to",
246+
)
247+
248+
x = 0.31
249+
y = 0.0
250+
z = 0.59
251+
252+
request = ManipulatorMoveTo.Request()
253+
request.target_pose = PoseStamped()
254+
request.target_pose.header.frame_id = self.manipulator_frame
255+
request.target_pose.pose = Pose(
256+
position=Point(x=x, y=y, z=z),
257+
orientation=self.quaternion,
258+
)
259+
260+
request.initial_gripper_state = True # open
261+
request.final_gripper_state = False # closed
262+
263+
future = client.call_async(request)
264+
self.connector.node.get_logger().debug(
265+
f"Calling ManipulatorMoveTo service with request: x={request.target_pose.pose.position.x:.2f}, y={request.target_pose.pose.position.y:.2f}, z={request.target_pose.pose.position.z:.2f}"
266+
)
267+
response = get_future_result(future, timeout_sec=5.0)
268+
269+
if response is None:
270+
return "Failed to reset the arm."
271+
272+
if response.success:
273+
return "Arm successfully reset."
274+
else:
275+
return "Failed to reset the arm."
276+

src/rai_extensions/rai_open_set_vision/rai_open_set_vision/agents/base_vision_agent.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ def __init__(
3636
os.makedirs(self._weights_path, exist_ok=True)
3737
self._init_weight_path()
3838
self.weight_path = self._weights_path
39-
self.ros2_connector = ROS2Connector(ros2_name)
39+
self.ros2_connector = ROS2Connector(ros2_name, executor_type="single_threaded")
4040

4141
def _init_weight_path(self):
4242
try:

0 commit comments

Comments
 (0)