agenticros 0.1.9 → 0.1.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +71 -4
- package/dist/commands/init.js.map +1 -1
- package/dist/menu.js +1 -1
- package/dist/menu.js.map +1 -1
- package/package.json +1 -1
- package/runtime/BUNDLE.json +1 -1
- package/runtime/ros2_ws/src/agenticros_sim/README.md +52 -13
- package/runtime/ros2_ws/src/agenticros_sim/config/arm_bridge.yaml +84 -0
- package/runtime/ros2_ws/src/agenticros_sim/config/arm_view.rviz +109 -0
- package/runtime/ros2_ws/src/agenticros_sim/launch/sim_arm.launch.py +223 -0
- package/runtime/ros2_ws/src/agenticros_sim/models/agenticros_amr/model.sdf +1 -1
- package/runtime/ros2_ws/src/agenticros_sim/models/agenticros_arm/model.config +26 -0
- package/runtime/ros2_ws/src/agenticros_sim/models/agenticros_arm/model.sdf +426 -0
- package/runtime/ros2_ws/src/agenticros_sim/urdf/agenticros_arm.urdf.xacro +205 -0
- package/runtime/ros2_ws/src/agenticros_sim/worlds/agenticros_indoor.sdf +1 -1
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
"""sim_arm.launch.py
|
|
2
|
+
|
|
3
|
+
Bring up the AgenticROS 6-DOF arm in Gazebo (Fortress / ign-gazebo 6 on
|
|
4
|
+
Humble Jetson, or Harmonic / gz-sim 8 on Jazzy) with full ROS-side
|
|
5
|
+
plumbing:
|
|
6
|
+
* gz sim agenticros_indoor.sdf (the world)
|
|
7
|
+
* ros_gz_sim create (spawn the arm)
|
|
8
|
+
* ros_gz_bridge parameter_bridge (gz <-> ROS topics)
|
|
9
|
+
* robot_state_publisher (URDF mirror) (for RViz RobotModel)
|
|
10
|
+
* Optional RViz (--rviz launch arg)
|
|
11
|
+
|
|
12
|
+
Joint commands are exposed as std_msgs/Float64 (radians) on:
|
|
13
|
+
/arm/shoulder_pan/cmd_pos
|
|
14
|
+
/arm/shoulder_lift/cmd_pos
|
|
15
|
+
/arm/elbow/cmd_pos
|
|
16
|
+
/arm/wrist_1/cmd_pos
|
|
17
|
+
/arm/wrist_2/cmd_pos
|
|
18
|
+
/arm/wrist_3/cmd_pos
|
|
19
|
+
|
|
20
|
+
Examples:
|
|
21
|
+
ros2 launch agenticros_sim sim_arm.launch.py
|
|
22
|
+
ros2 launch agenticros_sim sim_arm.launch.py use_rviz:=true
|
|
23
|
+
ros2 launch agenticros_sim sim_arm.launch.py gui:=false # headless
|
|
24
|
+
"""
|
|
25
|
+
|
|
26
|
+
from __future__ import annotations
|
|
27
|
+
|
|
28
|
+
import os
|
|
29
|
+
|
|
30
|
+
from ament_index_python.packages import get_package_share_directory
|
|
31
|
+
from launch import LaunchContext, LaunchDescription
|
|
32
|
+
from launch.actions import (
|
|
33
|
+
DeclareLaunchArgument,
|
|
34
|
+
ExecuteProcess,
|
|
35
|
+
IncludeLaunchDescription,
|
|
36
|
+
OpaqueFunction,
|
|
37
|
+
TimerAction,
|
|
38
|
+
)
|
|
39
|
+
from launch.conditions import IfCondition
|
|
40
|
+
from launch.launch_description_sources import PythonLaunchDescriptionSource
|
|
41
|
+
from launch.substitutions import Command, LaunchConfiguration, PathJoinSubstitution
|
|
42
|
+
from launch_ros.actions import Node
|
|
43
|
+
from launch_ros.parameter_descriptions import ParameterValue
|
|
44
|
+
from launch_ros.substitutions import FindPackageShare
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
PKG_NAME = "agenticros_sim"
|
|
48
|
+
|
|
49
|
+
# Default "home" pose, published once after spawn so the arm settles in a
|
|
50
|
+
# stable known configuration instead of whatever gravity happens to find:
|
|
51
|
+
# shoulder_pan = 0 (forward)
|
|
52
|
+
# shoulder_lift = -pi/2 (upper arm up)
|
|
53
|
+
# elbow = pi/2 (forearm horizontal, forming an L)
|
|
54
|
+
# wrist_* = 0
|
|
55
|
+
HOME_POSE = {
|
|
56
|
+
"shoulder_pan": 0.0,
|
|
57
|
+
"shoulder_lift": -1.5707963,
|
|
58
|
+
"elbow": 1.5707963,
|
|
59
|
+
"wrist_1": 0.0,
|
|
60
|
+
"wrist_2": 0.0,
|
|
61
|
+
"wrist_3": 0.0,
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
def generate_launch_description() -> LaunchDescription:
|
|
66
|
+
pkg_share = get_package_share_directory(PKG_NAME)
|
|
67
|
+
default_world = os.path.join(pkg_share, "worlds", "agenticros_indoor.sdf")
|
|
68
|
+
default_bridge = os.path.join(pkg_share, "config", "arm_bridge.yaml")
|
|
69
|
+
default_rviz = os.path.join(pkg_share, "config", "arm_view.rviz")
|
|
70
|
+
model_sdf = os.path.join(pkg_share, "models", "agenticros_arm", "model.sdf")
|
|
71
|
+
urdf_xacro = os.path.join(pkg_share, "urdf", "agenticros_arm.urdf.xacro")
|
|
72
|
+
|
|
73
|
+
world_arg = DeclareLaunchArgument(
|
|
74
|
+
"world", default_value=default_world,
|
|
75
|
+
description="SDF world file to load (absolute path).",
|
|
76
|
+
)
|
|
77
|
+
use_rviz_arg = DeclareLaunchArgument(
|
|
78
|
+
"use_rviz", default_value="false",
|
|
79
|
+
description="Open RViz with the arm view config.",
|
|
80
|
+
)
|
|
81
|
+
use_sim_time_arg = DeclareLaunchArgument(
|
|
82
|
+
"use_sim_time", default_value="true",
|
|
83
|
+
description="Tell ROS nodes to use /clock published by gz.",
|
|
84
|
+
)
|
|
85
|
+
# Spawn the arm well away from the AMR spawn point (which is 0,0) so users
|
|
86
|
+
# running the indoor world can see both side by side if curious.
|
|
87
|
+
x_arg = DeclareLaunchArgument("x", default_value="3.0", description="Arm spawn X (m)")
|
|
88
|
+
y_arg = DeclareLaunchArgument("y", default_value="0.0", description="Arm spawn Y (m)")
|
|
89
|
+
z_arg = DeclareLaunchArgument("z", default_value="0.0", description="Arm spawn Z (m)")
|
|
90
|
+
yaw_arg = DeclareLaunchArgument("yaw", default_value="0.0", description="Arm yaw (rad)")
|
|
91
|
+
bridge_arg = DeclareLaunchArgument(
|
|
92
|
+
"bridge_config_file", default_value=default_bridge,
|
|
93
|
+
description="ros_gz_bridge parameter_bridge config YAML.",
|
|
94
|
+
)
|
|
95
|
+
gui_arg = DeclareLaunchArgument(
|
|
96
|
+
"gui", default_value="true",
|
|
97
|
+
description="If 'false', run gz-sim headless (-s -r).",
|
|
98
|
+
)
|
|
99
|
+
rviz_config_arg = DeclareLaunchArgument(
|
|
100
|
+
"rviz_config", default_value=default_rviz,
|
|
101
|
+
description="RViz config path (used when use_rviz is true).",
|
|
102
|
+
)
|
|
103
|
+
|
|
104
|
+
# ---------- Spawn the arm ----------
|
|
105
|
+
spawn_arm = Node(
|
|
106
|
+
package="ros_gz_sim",
|
|
107
|
+
executable="create",
|
|
108
|
+
name="spawn_agenticros_arm",
|
|
109
|
+
output="screen",
|
|
110
|
+
arguments=[
|
|
111
|
+
"-name", "agenticros_arm",
|
|
112
|
+
"-file", model_sdf,
|
|
113
|
+
"-x", LaunchConfiguration("x"),
|
|
114
|
+
"-y", LaunchConfiguration("y"),
|
|
115
|
+
"-z", LaunchConfiguration("z"),
|
|
116
|
+
"-Y", LaunchConfiguration("yaw"),
|
|
117
|
+
],
|
|
118
|
+
)
|
|
119
|
+
|
|
120
|
+
# ---------- gz <-> ROS bridge ----------
|
|
121
|
+
bridge = Node(
|
|
122
|
+
package="ros_gz_bridge",
|
|
123
|
+
executable="parameter_bridge",
|
|
124
|
+
name="agenticros_arm_bridge",
|
|
125
|
+
output="screen",
|
|
126
|
+
parameters=[{
|
|
127
|
+
"config_file": LaunchConfiguration("bridge_config_file"),
|
|
128
|
+
"qos_overrides./tf_static.publisher.durability": "transient_local",
|
|
129
|
+
"use_sim_time": LaunchConfiguration("use_sim_time"),
|
|
130
|
+
}],
|
|
131
|
+
)
|
|
132
|
+
|
|
133
|
+
# ---------- robot_state_publisher (URDF mirror of the SDF) ----------
|
|
134
|
+
# Without this, RViz only has TF axes and won't draw the arm. The URDF is
|
|
135
|
+
# purely for visualization; physics, joint controllers, and gravity all
|
|
136
|
+
# live in the SDF.
|
|
137
|
+
# NOTE: `Command(... on_stderr='ignore')` keeps xacro's "redefining global
|
|
138
|
+
# symbol: pi" warnings from aborting the launch.
|
|
139
|
+
robot_description = ParameterValue(
|
|
140
|
+
Command(["xacro ", urdf_xacro], on_stderr="ignore"), value_type=str,
|
|
141
|
+
)
|
|
142
|
+
rsp = Node(
|
|
143
|
+
package="robot_state_publisher",
|
|
144
|
+
executable="robot_state_publisher",
|
|
145
|
+
name="robot_state_publisher",
|
|
146
|
+
output="screen",
|
|
147
|
+
parameters=[{
|
|
148
|
+
"robot_description": robot_description,
|
|
149
|
+
"use_sim_time": LaunchConfiguration("use_sim_time"),
|
|
150
|
+
}],
|
|
151
|
+
)
|
|
152
|
+
|
|
153
|
+
# ---------- Redundant home-pose publisher ----------
|
|
154
|
+
# The SDF already sets <initial_position> on the joints and the
|
|
155
|
+
# JointPositionController plugins so the arm spawns at home pose and
|
|
156
|
+
# the controllers hold it there immediately. This timer is a safety
|
|
157
|
+
# net: if a user `gz service`-spawned a fresh arm from a controller
|
|
158
|
+
# config that didn't include initial_position, this still gets it
|
|
159
|
+
# into a sane pose.
|
|
160
|
+
#
|
|
161
|
+
# `ros2 topic pub --once` is unreliable: the publisher exits before
|
|
162
|
+
# discovery completes, so the bridge often drops the message.
|
|
163
|
+
# `--times 5 --rate 5` publishes 5 copies over 1 s, which is enough
|
|
164
|
+
# for the bridge subscription to come up and consume at least one.
|
|
165
|
+
home_publishers = [
|
|
166
|
+
ExecuteProcess(
|
|
167
|
+
cmd=[
|
|
168
|
+
"ros2", "topic", "pub", "--times", "5", "--rate", "5",
|
|
169
|
+
f"/arm/{joint}/cmd_pos", "std_msgs/msg/Float64",
|
|
170
|
+
f"{{data: {angle}}}",
|
|
171
|
+
],
|
|
172
|
+
output="log",
|
|
173
|
+
)
|
|
174
|
+
for joint, angle in HOME_POSE.items()
|
|
175
|
+
]
|
|
176
|
+
home_pose_action = TimerAction(period=8.0, actions=home_publishers)
|
|
177
|
+
|
|
178
|
+
# ---------- Optional RViz ----------
|
|
179
|
+
rviz = Node(
|
|
180
|
+
package="rviz2",
|
|
181
|
+
executable="rviz2",
|
|
182
|
+
name="rviz2",
|
|
183
|
+
output="screen",
|
|
184
|
+
condition=IfCondition(LaunchConfiguration("use_rviz")),
|
|
185
|
+
arguments=["-d", LaunchConfiguration("rviz_config")],
|
|
186
|
+
parameters=[{"use_sim_time": LaunchConfiguration("use_sim_time")}],
|
|
187
|
+
)
|
|
188
|
+
|
|
189
|
+
return LaunchDescription([
|
|
190
|
+
world_arg,
|
|
191
|
+
use_rviz_arg,
|
|
192
|
+
use_sim_time_arg,
|
|
193
|
+
x_arg, y_arg, z_arg, yaw_arg,
|
|
194
|
+
bridge_arg,
|
|
195
|
+
gui_arg,
|
|
196
|
+
rviz_config_arg,
|
|
197
|
+
OpaqueFunction(function=_launch_gz_sim),
|
|
198
|
+
spawn_arm,
|
|
199
|
+
bridge,
|
|
200
|
+
rsp,
|
|
201
|
+
home_pose_action,
|
|
202
|
+
rviz,
|
|
203
|
+
])
|
|
204
|
+
|
|
205
|
+
|
|
206
|
+
def _launch_gz_sim(context: LaunchContext, *_, **__):
|
|
207
|
+
"""Resolve launch args and emit the gz_sim IncludeLaunchDescription action."""
|
|
208
|
+
gui = context.launch_configurations.get("gui", "true").lower() == "true"
|
|
209
|
+
world = context.launch_configurations.get(
|
|
210
|
+
"world",
|
|
211
|
+
os.path.join(get_package_share_directory(PKG_NAME), "worlds", "agenticros_indoor.sdf"),
|
|
212
|
+
)
|
|
213
|
+
gz_args = f"-r {world}" if gui else f"-r -s --headless-rendering {world}"
|
|
214
|
+
|
|
215
|
+
gz_launch = IncludeLaunchDescription(
|
|
216
|
+
PythonLaunchDescriptionSource(
|
|
217
|
+
PathJoinSubstitution(
|
|
218
|
+
[FindPackageShare("ros_gz_sim"), "launch", "gz_sim.launch.py"]
|
|
219
|
+
)
|
|
220
|
+
),
|
|
221
|
+
launch_arguments=[("gz_args", gz_args)],
|
|
222
|
+
)
|
|
223
|
+
return [gz_launch]
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
<?xml version="1.0"?>
|
|
2
|
+
<model>
|
|
3
|
+
<name>agenticros_arm</name>
|
|
4
|
+
<version>1.0</version>
|
|
5
|
+
<sdf version="1.10">model.sdf</sdf>
|
|
6
|
+
<author>
|
|
7
|
+
<name>AgenticROS</name>
|
|
8
|
+
<email>hello@agenticros.dev</email>
|
|
9
|
+
</author>
|
|
10
|
+
<description>
|
|
11
|
+
Six-DOF UR5e-shaped robotic arm for the AgenticROS Phase 3 simulation.
|
|
12
|
+
Approximates the UR5e joint topology (shoulder_pan, shoulder_lift, elbow,
|
|
13
|
+
wrist_1, wrist_2, wrist_3 + tool0 end-effector frame) using simple
|
|
14
|
+
cylindrical link geometry, gz-sim JointPositionController plugins per
|
|
15
|
+
joint, and PD gains tuned to hold the arm against gravity without
|
|
16
|
+
ros2_control or MoveIt2 in the loop.
|
|
17
|
+
|
|
18
|
+
Topic surface (Gazebo side; ros_gz_bridge re-emits as ROS topics):
|
|
19
|
+
/arm/JOINT/cmd_pos type=gz.msgs.Double ROS_TO_GZ
|
|
20
|
+
/joint_states type=gz.msgs.Model GZ_TO_ROS
|
|
21
|
+
/model/agenticros_arm/pose type=gz.msgs.Pose_V GZ_TO_ROS (to /tf)
|
|
22
|
+
|
|
23
|
+
Send a single joint angle as ROS std_msgs/Float64 (radians) to any
|
|
24
|
+
/arm/JOINT/cmd_pos topic and the controller drives the joint there.
|
|
25
|
+
</description>
|
|
26
|
+
</model>
|