agenticros 0.1.0 → 0.1.2

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.
Files changed (42) hide show
  1. package/dist/commands/config.d.ts.map +1 -1
  2. package/dist/commands/config.js +37 -1
  3. package/dist/commands/config.js.map +1 -1
  4. package/dist/commands/down.d.ts +6 -4
  5. package/dist/commands/down.d.ts.map +1 -1
  6. package/dist/commands/down.js +16 -6
  7. package/dist/commands/down.js.map +1 -1
  8. package/dist/commands/logs.js +2 -2
  9. package/dist/commands/logs.js.map +1 -1
  10. package/dist/commands/status.d.ts.map +1 -1
  11. package/dist/commands/status.js +10 -6
  12. package/dist/commands/status.js.map +1 -1
  13. package/dist/commands/up.d.ts +1 -0
  14. package/dist/commands/up.d.ts.map +1 -1
  15. package/dist/commands/up.js +33 -1
  16. package/dist/commands/up.js.map +1 -1
  17. package/dist/index.js +25 -4
  18. package/dist/index.js.map +1 -1
  19. package/dist/runners/sim.d.ts +2 -0
  20. package/dist/runners/sim.d.ts.map +1 -1
  21. package/dist/runners/sim.js +2 -0
  22. package/dist/runners/sim.js.map +1 -1
  23. package/package.json +1 -1
  24. package/runtime/BUNDLE.json +1 -1
  25. package/runtime/packages/core/src/transport/local/transport.ts +25 -5
  26. package/runtime/ros2_ws/src/agenticros_sim/CMakeLists.txt +25 -0
  27. package/runtime/ros2_ws/src/agenticros_sim/README.md +120 -0
  28. package/runtime/ros2_ws/src/agenticros_sim/config/agenticros-sim.config.json +28 -0
  29. package/runtime/ros2_ws/src/agenticros_sim/config/amr_bridge.yaml +111 -0
  30. package/runtime/ros2_ws/src/agenticros_sim/config/amr_view.rviz +192 -0
  31. package/runtime/ros2_ws/src/agenticros_sim/env-hooks/gz_resource_path.dsv.in +3 -0
  32. package/runtime/ros2_ws/src/agenticros_sim/env-hooks/gz_resource_path.sh.in +7 -0
  33. package/runtime/ros2_ws/src/agenticros_sim/launch/sim_amr.launch.py +184 -0
  34. package/runtime/ros2_ws/src/agenticros_sim/models/agenticros_amr/model.config +17 -0
  35. package/runtime/ros2_ws/src/agenticros_sim/models/agenticros_amr/model.sdf +251 -0
  36. package/runtime/ros2_ws/src/agenticros_sim/package.xml +27 -0
  37. package/runtime/ros2_ws/src/agenticros_sim/urdf/agenticros_amr.urdf.xacro +127 -0
  38. package/runtime/ros2_ws/src/agenticros_sim/worlds/agenticros_indoor.sdf +183 -0
  39. package/runtime/scripts/configure_for_sim.sh +64 -0
  40. package/runtime/scripts/sim/run_sim.sh +169 -0
  41. package/runtime/scripts/test-follow-me-sim.mjs +135 -0
  42. package/runtime/scripts/test-mcp-e2e.mjs +184 -0
@@ -0,0 +1,120 @@
1
+ # agenticros_sim
2
+
3
+ Gazebo Harmonic simulation assets for the AgenticROS project: an indoor world,
4
+ a 2-wheel diff-drive AMR with a depth camera + 2D lidar + IMU, and a `ros_gz_
5
+ bridge` config that exposes everything on the topic names the real-robot
6
+ plugin already expects.
7
+
8
+ ## What's inside
9
+
10
+ ```
11
+ agenticros_sim/
12
+ ├── worlds/agenticros_indoor.sdf 12 x 12 m indoor room with obstacles
13
+ │ and one "person" target for follow-me
14
+ ├── models/agenticros_amr/ 2-wheel diff-drive AMR with sensors
15
+ │ ├── model.config
16
+ │ └── model.sdf
17
+ ├── config/
18
+ │ ├── amr_bridge.yaml gz <-> ROS topic mapping
19
+ │ └── amr_view.rviz RViz config showing camera, scan, TF
20
+ ├── launch/sim_amr.launch.py One-stop launcher
21
+ ├── env-hooks/ Add the package's share/ to GZ_SIM_RESOURCE_PATH
22
+ └── CMakeLists.txt + package.xml Standard ament_cmake skeleton
23
+ ```
24
+
25
+ ## Quick start
26
+
27
+ ```bash
28
+ # Easiest: use the agenticros CLI (handles ROS sourcing + workspace build).
29
+ agenticros up sim-amr # GUI
30
+ agenticros up sim-amr --rviz # GUI + RViz panel
31
+ agenticros up sim-amr --no-camera # (no effect for sim - flag is real-only)
32
+
33
+ # Or run the launch file directly:
34
+ cd ros2_ws && colcon build --symlink-install --packages-select agenticros_sim
35
+ source install/setup.bash
36
+ ros2 launch agenticros_sim sim_amr.launch.py
37
+ ros2 launch agenticros_sim sim_amr.launch.py use_rviz:=true
38
+ ros2 launch agenticros_sim sim_amr.launch.py gui:=false # headless
39
+ ```
40
+
41
+ ## Topic layout
42
+
43
+ The bridge YAML deliberately matches the real-robot AgenticROS plugin's topic
44
+ names so any code that works against the real RealSense + diff-drive base
45
+ works against sim without configuration changes.
46
+
47
+ | Topic | Type | Direction |
48
+ |---------------------------------------------|---------------------------------|-----------|
49
+ | `/cmd_vel` | `geometry_msgs/msg/Twist` | ROS -> GZ |
50
+ | `/odom` | `nav_msgs/msg/Odometry` | GZ -> ROS |
51
+ | `/tf`, `/tf_static` | `tf2_msgs/msg/TFMessage` | GZ -> ROS |
52
+ | `/joint_states` | `sensor_msgs/msg/JointState` | GZ -> ROS |
53
+ | `/camera/camera/color/image_raw` | `sensor_msgs/msg/Image` | GZ -> ROS |
54
+ | `/camera/camera/color/camera_info` | `sensor_msgs/msg/CameraInfo` | GZ -> ROS |
55
+ | `/camera/camera/depth/image_rect_raw` | `sensor_msgs/msg/Image` (32FC1) | GZ -> ROS |
56
+ | `/camera/camera/depth/camera_info` | `sensor_msgs/msg/CameraInfo` | GZ -> ROS |
57
+ | `/camera/camera/depth/points` | `sensor_msgs/msg/PointCloud2` | GZ -> ROS |
58
+ | `/scan` | `sensor_msgs/msg/LaserScan` | GZ -> ROS |
59
+ | `/imu/data` | `sensor_msgs/msg/Imu` | GZ -> ROS |
60
+ | `/clock` | `rosgraph_msgs/msg/Clock` | GZ -> ROS |
61
+
62
+ ## AMR specs
63
+
64
+ | Property | Value |
65
+ |-------------------------|-------------------------------------------|
66
+ | Footprint | 0.40 m x 0.30 m chassis |
67
+ | Wheel diameter | 0.16 m |
68
+ | Wheel separation | 0.36 m |
69
+ | Front sensor (RGBD) | 640 x 480, 30 Hz, 87° HFOV (D435-like) |
70
+ | Depth encoding | 32FC1 (float32 metres) |
71
+ | LIDAR | 360 samples, 12 Hz, 12 m range |
72
+ | IMU | 100 Hz, mild gaussian noise |
73
+ | Max linear acceleration | 1.0 m/s² |
74
+ | Max angular acceleration| 2.0 rad/s² |
75
+
76
+ ## Notes & gotchas
77
+
78
+ - **Depth encoding**: the `rgbd_camera` plugin actually emits **16UC1 in
79
+ millimetres** when bridged via `ros_gz_bridge` on Humble. This matches the
80
+ real RealSense D435 driver's default 16UC1/mm encoding — the AgenticROS
81
+ depth-loop handles it natively. (Newer Gazebo versions may default to 32FC1;
82
+ the depth-loop normaliser handles both.)
83
+ - **`use_sim_time`**: defaulted to `true`. Any downstream node that subscribes
84
+ to bridged topics should also set `use_sim_time:=true`, or it will mismatch
85
+ timestamps.
86
+ - **Heavy worlds**: the indoor world is intentionally tiny so it runs on
87
+ Jetson-class hardware. For bigger demos, use the `world` launch arg with
88
+ one of the upstream `gazebo_models_worlds_collection` SDFs.
89
+ - **Why two TF bridges?** `/tf` is bridged as a regular topic, while
90
+ `/tf_static` rides over the pose_static endpoint with a transient_local QoS
91
+ override applied in the launch file.
92
+
93
+ ## Known sharp edges (Phase 2 smoke-test findings on Jetson + Humble)
94
+
95
+ These are non-fatal but worth knowing as you build sim demos:
96
+
97
+ 1. **`/odom` does not flow through the bridge.** The gz-sim diff-drive plugin
98
+ publishes `gz.msgs.Odometry` to `/odometry`, but `ros_gz_bridge` on Humble
99
+ appears to expect `gz.msgs.OdometryWithCovariance` for the
100
+ `nav_msgs/msg/Odometry` mapping. The other transforms (`/tf`, `/tf_static`)
101
+ work and are usually enough for navigation demos. Fix candidates:
102
+ add an `<odom_publisher_topic>` for `_with_covariance` in the diff-drive
103
+ config, or write a tiny relay node. Tracked for Phase 4 polish.
104
+ 2. **`/camera/camera/color/image_raw` is silent in headless mode** on this
105
+ Jetson (`libEGL: failed to create dri2 screen`). Depth, lidar, IMU, and
106
+ joint_states all stream correctly regardless. With `gui:=true` (a real
107
+ display attached) RGB recovers. Run `gz sim --versions` to make sure
108
+ you're on Harmonic; older Garden / Citadel may have a different EGL path.
109
+ 3. **gz CLI tools (`gz topic -e`, `gz topic --info`) sometimes can't reach
110
+ the running simulator** because gz publishes on the Docker bridge IP
111
+ (`172.17.0.1`) on this host. The ROS-side bridge still subscribes
112
+ successfully — you just won't be able to debug-echo at the gz layer. Use
113
+ ROS-side `ros2 topic` commands instead.
114
+ 4. **Depth values can saturate well past `<far>`** when no surface is in the
115
+ camera frustum. The follow-me-depth algorithm clamps to `[0.5 m, 4.0 m]`,
116
+ which inherently filters this; if you write your own depth consumer,
117
+ add the same clamp.
118
+ 5. **Two `set` lines:** `run_sim.sh` uses `set -eo pipefail` (not `set -u`)
119
+ because the ROS 2 `setup.bash` references some variables before defining
120
+ them, which would otherwise abort the script.
@@ -0,0 +1,28 @@
1
+ {
2
+ "$comment": "AgenticROS config template tuned for sim-amr. Drop this in ~/.agenticros/config.json (or run `agenticros init` and answer 'simulation') to point the MCP server + OpenClaw plugin at the sim's topics. All values match agenticros_sim/config/amr_bridge.yaml. NOTE: robot.namespace is intentionally empty - the sim bridge publishes /cmd_vel, /scan, /imu/data, etc. at the graph root (no robot prefix), so AgenticROS must NOT namespace topics. For multi-robot sim, prefix the topics in amr_bridge.yaml and set namespace here to match.",
3
+ "transport": {
4
+ "mode": "local"
5
+ },
6
+ "robot": {
7
+ "namespace": "",
8
+ "name": "Sim AMR",
9
+ "cameraTopic": "/camera/camera/color/image_raw"
10
+ },
11
+ "safety": {
12
+ "maxLinearVelocity": 0.5,
13
+ "maxAngularVelocity": 1.0
14
+ },
15
+ "teleop": {
16
+ "cmdVelTopic": "/cmd_vel",
17
+ "speedDefault": 0.2,
18
+ "cameraTopics": [
19
+ { "topic": "/camera/camera/color/image_raw", "label": "Sim RGB" },
20
+ { "topic": "/camera/camera/depth/image_rect_raw", "label": "Sim depth" }
21
+ ]
22
+ },
23
+ "skills": {
24
+ "followme": {
25
+ "depthTopic": "/camera/camera/depth/image_rect_raw"
26
+ }
27
+ }
28
+ }
@@ -0,0 +1,111 @@
1
+ # amr_bridge.yaml
2
+ #
3
+ # Maps Gazebo Harmonic topics produced by the AMR model + world plugins to
4
+ # ROS 2 topics on the names the real-robot AgenticROS plugin already expects.
5
+ # Used by ros_gz_bridge's parameter_bridge node via the `config_file` arg.
6
+ #
7
+ # Key invariant: the camera topic names below match the RealSense ROS driver
8
+ # defaults (`/camera/camera/color/image_raw`, `/camera/camera/depth/image_rect_raw`)
9
+ # so plugin code that targets real hardware works against sim without any
10
+ # config change. Same for /cmd_vel, /odom, /scan, /imu/data, /tf.
11
+ #
12
+ # Direction notation: GZ_TO_ROS — gazebo publishes, ros subscribes (sensors)
13
+ # ROS_TO_GZ — ros publishes, gazebo subscribes (cmd_vel)
14
+ # BIDIRECTIONAL — rare, /tf for example
15
+ #
16
+ # Field reference: https://github.com/gazebosim/ros_gz/blob/humble/ros_gz_bridge/README.md
17
+
18
+ # ---------------- cmd_vel (ROS -> GZ) ----------------
19
+ - ros_topic_name: "/cmd_vel"
20
+ gz_topic_name: "/model/agenticros_amr/cmd_vel"
21
+ ros_type_name: "geometry_msgs/msg/Twist"
22
+ gz_type_name: "gz.msgs.Twist"
23
+ direction: ROS_TO_GZ
24
+
25
+ # ---------------- odometry (GZ -> ROS) ----------------
26
+ # Note: the gz-sim diff-drive system publishes <odom_topic> as a bare topic
27
+ # (no /model/<name>/ prefix), unlike <topic> which DOES get prefixed.
28
+ - ros_topic_name: "/odom"
29
+ gz_topic_name: "/odometry"
30
+ ros_type_name: "nav_msgs/msg/Odometry"
31
+ gz_type_name: "gz.msgs.Odometry"
32
+ direction: GZ_TO_ROS
33
+
34
+ # ---------------- /tf (GZ -> ROS) ----------------
35
+ - ros_topic_name: "/tf"
36
+ gz_topic_name: "/tf"
37
+ ros_type_name: "tf2_msgs/msg/TFMessage"
38
+ gz_type_name: "gz.msgs.Pose_V"
39
+ direction: GZ_TO_ROS
40
+
41
+ # ---------------- pose info (GZ -> ROS) ----------------
42
+ - ros_topic_name: "/tf_static"
43
+ gz_topic_name: "/model/agenticros_amr/pose_static"
44
+ ros_type_name: "tf2_msgs/msg/TFMessage"
45
+ gz_type_name: "gz.msgs.Pose_V"
46
+ direction: GZ_TO_ROS
47
+
48
+ # ---------------- joint states (GZ -> ROS) ----------------
49
+ - ros_topic_name: "/joint_states"
50
+ gz_topic_name: "/joint_states"
51
+ ros_type_name: "sensor_msgs/msg/JointState"
52
+ gz_type_name: "gz.msgs.Model"
53
+ direction: GZ_TO_ROS
54
+
55
+ # ---------------- Depth camera (GZ -> ROS) ----------------
56
+ # The rgbd_camera plugin publishes under <topic>camera</topic>, which becomes:
57
+ # /camera/image (RGB)
58
+ # /camera/depth_image (depth, 32FC1)
59
+ # /camera/points (PointCloud2)
60
+ # /camera/camera_info (CameraInfo)
61
+ # We remap each to the RealSense layout the real-robot plugin expects.
62
+ - ros_topic_name: "/camera/camera/color/image_raw"
63
+ gz_topic_name: "/camera/image"
64
+ ros_type_name: "sensor_msgs/msg/Image"
65
+ gz_type_name: "gz.msgs.Image"
66
+ direction: GZ_TO_ROS
67
+
68
+ - ros_topic_name: "/camera/camera/color/camera_info"
69
+ gz_topic_name: "/camera/camera_info"
70
+ ros_type_name: "sensor_msgs/msg/CameraInfo"
71
+ gz_type_name: "gz.msgs.CameraInfo"
72
+ direction: GZ_TO_ROS
73
+
74
+ - ros_topic_name: "/camera/camera/depth/image_rect_raw"
75
+ gz_topic_name: "/camera/depth_image"
76
+ ros_type_name: "sensor_msgs/msg/Image"
77
+ gz_type_name: "gz.msgs.Image"
78
+ direction: GZ_TO_ROS
79
+
80
+ - ros_topic_name: "/camera/camera/depth/camera_info"
81
+ gz_topic_name: "/camera/depth_image/camera_info"
82
+ ros_type_name: "sensor_msgs/msg/CameraInfo"
83
+ gz_type_name: "gz.msgs.CameraInfo"
84
+ direction: GZ_TO_ROS
85
+
86
+ - ros_topic_name: "/camera/camera/depth/points"
87
+ gz_topic_name: "/camera/points"
88
+ ros_type_name: "sensor_msgs/msg/PointCloud2"
89
+ gz_type_name: "gz.msgs.PointCloudPacked"
90
+ direction: GZ_TO_ROS
91
+
92
+ # ---------------- 2D LIDAR (GZ -> ROS) ----------------
93
+ - ros_topic_name: "/scan"
94
+ gz_topic_name: "/scan"
95
+ ros_type_name: "sensor_msgs/msg/LaserScan"
96
+ gz_type_name: "gz.msgs.LaserScan"
97
+ direction: GZ_TO_ROS
98
+
99
+ # ---------------- IMU (GZ -> ROS) ----------------
100
+ - ros_topic_name: "/imu/data"
101
+ gz_topic_name: "/imu"
102
+ ros_type_name: "sensor_msgs/msg/Imu"
103
+ gz_type_name: "gz.msgs.IMU"
104
+ direction: GZ_TO_ROS
105
+
106
+ # ---------------- Clock (GZ -> ROS) ----------------
107
+ - ros_topic_name: "/clock"
108
+ gz_topic_name: "/clock"
109
+ ros_type_name: "rosgraph_msgs/msg/Clock"
110
+ gz_type_name: "gz.msgs.Clock"
111
+ direction: GZ_TO_ROS
@@ -0,0 +1,192 @@
1
+ Panels:
2
+ - Class: rviz_common/Displays
3
+ Help Height: 0
4
+ Name: Displays
5
+ Property Tree Widget:
6
+ Expanded:
7
+ - /TF1
8
+ Splitter Ratio: 0.5
9
+ Tree Height: 600
10
+ - Class: rviz_common/Views
11
+ Expanded:
12
+ - /Current View1
13
+ Name: Views
14
+ Splitter Ratio: 0.5
15
+ Visualization Manager:
16
+ Class: ""
17
+ Displays:
18
+ - Alpha: 0.5
19
+ Cell Size: 1
20
+ Class: rviz_default_plugins/Grid
21
+ Color: 160; 160; 164
22
+ Enabled: true
23
+ Line Style:
24
+ Line Width: 0.03
25
+ Value: Lines
26
+ Name: Grid
27
+ Normal Cell Count: 0
28
+ Offset:
29
+ X: 0
30
+ Y: 0
31
+ Z: 0
32
+ Plane: XY
33
+ Plane Cell Count: 20
34
+ Reference Frame: <Fixed Frame>
35
+ Value: true
36
+ - Class: rviz_default_plugins/TF
37
+ Enabled: true
38
+ Frame Timeout: 15
39
+ Frames:
40
+ All Enabled: true
41
+ Marker Scale: 0.5
42
+ Name: TF
43
+ Show Arrows: true
44
+ Show Axes: true
45
+ Show Names: true
46
+ Update Interval: 0
47
+ Value: true
48
+ - Alpha: 1
49
+ Class: rviz_default_plugins/RobotModel
50
+ Collision Enabled: false
51
+ Description File: ""
52
+ Description Source: Topic
53
+ Description Topic:
54
+ Depth: 5
55
+ Durability Policy: Volatile
56
+ History Policy: Keep Last
57
+ Reliability Policy: Reliable
58
+ Value: /robot_description
59
+ Enabled: true
60
+ Mass Properties:
61
+ Inertia: false
62
+ Mass: false
63
+ Name: RobotModel
64
+ TF Prefix: ""
65
+ Update Interval: 0
66
+ Value: true
67
+ Visual Enabled: true
68
+ - Alpha: 1
69
+ Autocompute Intensity Bounds: true
70
+ Autocompute Value Bounds:
71
+ Max Value: 10
72
+ Min Value: -10
73
+ Value: true
74
+ Axis: Z
75
+ Channel Name: intensity
76
+ Class: rviz_default_plugins/LaserScan
77
+ Color: 255; 255; 255
78
+ Color Transformer: Intensity
79
+ Decay Time: 0
80
+ Enabled: true
81
+ Invert Rainbow: false
82
+ Max Color: 255; 255; 255
83
+ Max Intensity: 4096
84
+ Min Color: 0; 0; 0
85
+ Min Intensity: 0
86
+ Name: LaserScan
87
+ Position Transformer: XYZ
88
+ Queue Size: 10
89
+ Selectable: true
90
+ Size (Pixels): 3
91
+ Size (m): 0.05
92
+ Style: Points
93
+ Topic:
94
+ Depth: 5
95
+ Durability Policy: Volatile
96
+ Filter size: 10
97
+ History Policy: Keep Last
98
+ Reliability Policy: Reliable
99
+ Value: /scan
100
+ Use Fixed Frame: true
101
+ Use rainbow: true
102
+ Value: true
103
+ - Class: rviz_default_plugins/Image
104
+ Enabled: true
105
+ Image Topic:
106
+ Depth: 5
107
+ Durability Policy: Volatile
108
+ History Policy: Keep Last
109
+ Reliability Policy: Reliable
110
+ Value: /camera/camera/color/image_raw
111
+ Max Value: 1
112
+ Median window: 5
113
+ Min Value: 0
114
+ Name: RGB
115
+ Normalize Range: true
116
+ Value: true
117
+ - Alpha: 1
118
+ Autocompute Intensity Bounds: true
119
+ Autocompute Value Bounds:
120
+ Max Value: 10
121
+ Min Value: -10
122
+ Value: true
123
+ Axis: Z
124
+ Channel Name: intensity
125
+ Class: rviz_default_plugins/PointCloud2
126
+ Color: 255; 255; 255
127
+ Color Transformer: AxisColor
128
+ Decay Time: 0
129
+ Enabled: true
130
+ Invert Rainbow: false
131
+ Max Color: 255; 255; 255
132
+ Max Intensity: 4096
133
+ Min Color: 0; 0; 0
134
+ Min Intensity: 0
135
+ Name: DepthCloud
136
+ Position Transformer: XYZ
137
+ Queue Size: 10
138
+ Selectable: true
139
+ Size (Pixels): 3
140
+ Size (m): 0.02
141
+ Style: Points
142
+ Topic:
143
+ Depth: 5
144
+ Durability Policy: Volatile
145
+ Filter size: 10
146
+ History Policy: Keep Last
147
+ Reliability Policy: Best Effort
148
+ Value: /camera/camera/depth/points
149
+ Use Fixed Frame: true
150
+ Use rainbow: true
151
+ Value: true
152
+ Enabled: true
153
+ Global Options:
154
+ Background Color: 48; 48; 48
155
+ Fixed Frame: odom
156
+ Frame Rate: 30
157
+ Name: root
158
+ Tools:
159
+ - Class: rviz_default_plugins/Interact
160
+ Hide Inactive Objects: true
161
+ - Class: rviz_default_plugins/MoveCamera
162
+ - Class: rviz_default_plugins/Select
163
+ - Class: rviz_default_plugins/FocusCamera
164
+ - Class: rviz_default_plugins/Measure
165
+ Line color: 128; 128; 0
166
+ Transformation:
167
+ Current:
168
+ Class: rviz_default_plugins/TF
169
+ Value: true
170
+ Views:
171
+ Current:
172
+ Class: rviz_default_plugins/Orbit
173
+ Distance: 7
174
+ Enable Stereo Rendering:
175
+ Stereo Eye Separation: 0.0599999987
176
+ Stereo Focal Distance: 1
177
+ Swap Stereo Eyes: false
178
+ Value: false
179
+ Focal Point:
180
+ X: 0
181
+ Y: 0
182
+ Z: 0
183
+ Focal Shape Fixed Size: true
184
+ Focal Shape Size: 0.05
185
+ Invert Z Axis: false
186
+ Name: Current View
187
+ Near Clip Distance: 0.01
188
+ Pitch: 0.5
189
+ Target Frame: <Fixed Frame>
190
+ Value: Orbit (rviz)
191
+ Yaw: -0.785
192
+ Saved: ~
@@ -0,0 +1,3 @@
1
+ prepend-non-duplicate;GZ_SIM_RESOURCE_PATH;share/@PROJECT_NAME@
2
+ prepend-non-duplicate;GZ_SIM_RESOURCE_PATH;share/@PROJECT_NAME@/models
3
+ prepend-non-duplicate;GZ_SIM_RESOURCE_PATH;share/@PROJECT_NAME@/worlds
@@ -0,0 +1,7 @@
1
+ # Generated env hook — prepends the agenticros_sim share/ tree onto the
2
+ # Gazebo Harmonic resource search path so `gz sim agenticros_indoor.sdf` and
3
+ # `<uri>model://agenticros_amr</uri>` resolve without absolute paths.
4
+
5
+ ament_prepend_unique_value GZ_SIM_RESOURCE_PATH "@CMAKE_INSTALL_PREFIX@/share/@PROJECT_NAME@"
6
+ ament_prepend_unique_value GZ_SIM_RESOURCE_PATH "@CMAKE_INSTALL_PREFIX@/share/@PROJECT_NAME@/models"
7
+ ament_prepend_unique_value GZ_SIM_RESOURCE_PATH "@CMAKE_INSTALL_PREFIX@/share/@PROJECT_NAME@/worlds"
@@ -0,0 +1,184 @@
1
+ """sim_amr.launch.py
2
+
3
+ Bring up the AgenticROS 2-wheel AMR in Gazebo Harmonic with full ROS-side
4
+ plumbing:
5
+ * gz sim agenticros_indoor.sdf (the world + everything in it)
6
+ * ros_gz_sim create (spawn the AMR if it isn't
7
+ already baked into the world)
8
+ * ros_gz_bridge parameter_bridge config_file (gz <-> ROS topic bridge)
9
+ * Optional RViz (--rviz launch arg)
10
+
11
+ Launch args:
12
+ world (default 'agenticros_indoor.sdf') Override the world file.
13
+ use_rviz (default 'false') Show RViz with the AMR config.
14
+ use_sim_time (default 'true') /clock is bridged; downstream
15
+ nodes should honour this.
16
+ x, y, z, yaw Spawn pose for the AMR.
17
+ bridge_config_file Override the bridge YAML.
18
+ gui (default 'true') Headless if 'false' (CI / docker).
19
+
20
+ Examples:
21
+ ros2 launch agenticros_sim sim_amr.launch.py
22
+ ros2 launch agenticros_sim sim_amr.launch.py use_rviz:=true
23
+ ros2 launch agenticros_sim sim_amr.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
+ IncludeLaunchDescription,
35
+ OpaqueFunction,
36
+ )
37
+ from launch.conditions import IfCondition
38
+ from launch.launch_description_sources import PythonLaunchDescriptionSource
39
+ from launch.substitutions import LaunchConfiguration, PathJoinSubstitution
40
+ from launch_ros.actions import Node
41
+ from launch_ros.substitutions import FindPackageShare
42
+ from launch_ros.parameter_descriptions import ParameterValue
43
+ from launch.substitutions import Command
44
+
45
+
46
+ PKG_NAME = "agenticros_sim"
47
+
48
+
49
+ def generate_launch_description() -> LaunchDescription:
50
+ pkg_share = get_package_share_directory(PKG_NAME)
51
+ default_world = os.path.join(pkg_share, "worlds", "agenticros_indoor.sdf")
52
+ default_bridge = os.path.join(pkg_share, "config", "amr_bridge.yaml")
53
+ default_rviz = os.path.join(pkg_share, "config", "amr_view.rviz")
54
+ model_sdf = os.path.join(pkg_share, "models", "agenticros_amr", "model.sdf")
55
+ urdf_xacro = os.path.join(pkg_share, "urdf", "agenticros_amr.urdf.xacro")
56
+
57
+ # --- Launch arguments ---
58
+ world_arg = DeclareLaunchArgument(
59
+ "world", default_value=default_world,
60
+ description="SDF world file to load (absolute path).",
61
+ )
62
+ use_rviz_arg = DeclareLaunchArgument(
63
+ "use_rviz", default_value="false",
64
+ description="Open RViz with the AMR view config.",
65
+ )
66
+ use_sim_time_arg = DeclareLaunchArgument(
67
+ "use_sim_time", default_value="true",
68
+ description="Tell ROS nodes to use /clock published by gz.",
69
+ )
70
+ x_arg = DeclareLaunchArgument("x", default_value="0.0", description="AMR spawn X (m)")
71
+ y_arg = DeclareLaunchArgument("y", default_value="0.0", description="AMR spawn Y (m)")
72
+ z_arg = DeclareLaunchArgument("z", default_value="0.1", description="AMR spawn Z (m)")
73
+ yaw_arg = DeclareLaunchArgument("yaw", default_value="0.0", description="AMR yaw (rad)")
74
+ bridge_arg = DeclareLaunchArgument(
75
+ "bridge_config_file", default_value=default_bridge,
76
+ description="ros_gz_bridge parameter_bridge config YAML.",
77
+ )
78
+ gui_arg = DeclareLaunchArgument(
79
+ "gui", default_value="true",
80
+ description="If 'false', run gz-sim headless (-s -r).",
81
+ )
82
+ rviz_config_arg = DeclareLaunchArgument(
83
+ "rviz_config", default_value=default_rviz,
84
+ description="RViz config path (used when use_rviz is true).",
85
+ )
86
+
87
+ # ---------- Spawn the AMR ----------
88
+ spawn_amr = Node(
89
+ package="ros_gz_sim",
90
+ executable="create",
91
+ name="spawn_agenticros_amr",
92
+ output="screen",
93
+ arguments=[
94
+ "-name", "agenticros_amr",
95
+ "-file", model_sdf,
96
+ "-x", LaunchConfiguration("x"),
97
+ "-y", LaunchConfiguration("y"),
98
+ "-z", LaunchConfiguration("z"),
99
+ "-Y", LaunchConfiguration("yaw"),
100
+ ],
101
+ )
102
+
103
+ # ---------- gz <-> ROS bridge ----------
104
+ bridge = Node(
105
+ package="ros_gz_bridge",
106
+ executable="parameter_bridge",
107
+ name="agenticros_amr_bridge",
108
+ output="screen",
109
+ parameters=[{
110
+ "config_file": LaunchConfiguration("bridge_config_file"),
111
+ "qos_overrides./tf_static.publisher.durability": "transient_local",
112
+ "use_sim_time": LaunchConfiguration("use_sim_time"),
113
+ }],
114
+ )
115
+
116
+ # ---------- robot_state_publisher (URDF mirror of the SDF) ----------
117
+ # Without this, RViz only has TF axes - it doesn't know the robot's geometry
118
+ # and can't render a 3D model in the RobotModel display. The URDF is purely
119
+ # for visualization; physics + sensors stay in the SDF.
120
+ # NOTE: `Command(... on_stderr='ignore')` is critical - xacro often prints
121
+ # benign warnings ("redefining global symbol: pi", etc.) to stderr, and the
122
+ # default behaviour of Command is to FAIL the launch on any stderr output.
123
+ robot_description = ParameterValue(
124
+ Command(["xacro ", urdf_xacro], on_stderr="ignore"), value_type=str,
125
+ )
126
+ rsp = Node(
127
+ package="robot_state_publisher",
128
+ executable="robot_state_publisher",
129
+ name="robot_state_publisher",
130
+ output="screen",
131
+ parameters=[{
132
+ "robot_description": robot_description,
133
+ "use_sim_time": LaunchConfiguration("use_sim_time"),
134
+ }],
135
+ )
136
+
137
+ # ---------- Optional RViz ----------
138
+ rviz = Node(
139
+ package="rviz2",
140
+ executable="rviz2",
141
+ name="rviz2",
142
+ output="screen",
143
+ condition=IfCondition(LaunchConfiguration("use_rviz")),
144
+ arguments=["-d", LaunchConfiguration("rviz_config")],
145
+ parameters=[{"use_sim_time": LaunchConfiguration("use_sim_time")}],
146
+ )
147
+
148
+ # The gz sim launcher needs a single space-separated `gz_args` string. We
149
+ # build it inside an OpaqueFunction so the conditional headless flag is
150
+ # evaluated at launch-time (substitutions can't do string concatenation).
151
+ return LaunchDescription([
152
+ world_arg,
153
+ use_rviz_arg,
154
+ use_sim_time_arg,
155
+ x_arg, y_arg, z_arg, yaw_arg,
156
+ bridge_arg,
157
+ gui_arg,
158
+ rviz_config_arg,
159
+ OpaqueFunction(function=_launch_gz_sim),
160
+ spawn_amr,
161
+ bridge,
162
+ rsp,
163
+ rviz,
164
+ ])
165
+
166
+
167
+ def _launch_gz_sim(context: LaunchContext, *_, **__):
168
+ """Resolve launch args and emit the gz_sim IncludeLaunchDescription action."""
169
+ gui = context.launch_configurations.get("gui", "true").lower() == "true"
170
+ world = context.launch_configurations.get(
171
+ "world",
172
+ os.path.join(get_package_share_directory(PKG_NAME), "worlds", "agenticros_indoor.sdf"),
173
+ )
174
+ gz_args = f"-r {world}" if gui else f"-r -s --headless-rendering {world}"
175
+
176
+ gz_launch = IncludeLaunchDescription(
177
+ PythonLaunchDescriptionSource(
178
+ PathJoinSubstitution(
179
+ [FindPackageShare("ros_gz_sim"), "launch", "gz_sim.launch.py"]
180
+ )
181
+ ),
182
+ launch_arguments=[("gz_args", gz_args)],
183
+ )
184
+ return [gz_launch]
@@ -0,0 +1,17 @@
1
+ <?xml version="1.0"?>
2
+ <model>
3
+ <name>AgenticROS AMR</name>
4
+ <version>0.1</version>
5
+ <sdf version="1.10">model.sdf</sdf>
6
+ <author>
7
+ <name>PlaiPin</name>
8
+ <email>hello@plaipin.com</email>
9
+ </author>
10
+ <description>
11
+ Two-wheel differential-drive AMR with a forward-facing RealSense-D435-style
12
+ depth camera, a 2D GPU lidar, and an IMU. Topic layout matches the real
13
+ AgenticROS robot (camera/camera/color/image_raw, camera/camera/depth/
14
+ image_rect_raw, scan, imu/data, odom, cmd_vel) so plugin code is identical
15
+ in real and sim.
16
+ </description>
17
+ </model>