agenticros 0.1.8 → 0.1.10

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 (31) hide show
  1. package/dist/commands/config.d.ts.map +1 -1
  2. package/dist/commands/config.js +36 -1
  3. package/dist/commands/config.js.map +1 -1
  4. package/dist/commands/doctor.d.ts.map +1 -1
  5. package/dist/commands/doctor.js +39 -0
  6. package/dist/commands/doctor.js.map +1 -1
  7. package/dist/commands/init.d.ts.map +1 -1
  8. package/dist/commands/init.js +7 -0
  9. package/dist/commands/init.js.map +1 -1
  10. package/dist/commands/up.d.ts.map +1 -1
  11. package/dist/commands/up.js +54 -1
  12. package/dist/commands/up.js.map +1 -1
  13. package/dist/index.js +8 -1
  14. package/dist/index.js.map +1 -1
  15. package/dist/menu.js +1 -1
  16. package/dist/menu.js.map +1 -1
  17. package/dist/util/profiles.d.ts +50 -0
  18. package/dist/util/profiles.d.ts.map +1 -0
  19. package/dist/util/profiles.js +173 -0
  20. package/dist/util/profiles.js.map +1 -0
  21. package/package.json +1 -1
  22. package/runtime/BUNDLE.json +1 -1
  23. package/runtime/ros2_ws/src/agenticros_sim/README.md +52 -13
  24. package/runtime/ros2_ws/src/agenticros_sim/config/arm_bridge.yaml +84 -0
  25. package/runtime/ros2_ws/src/agenticros_sim/config/arm_view.rviz +109 -0
  26. package/runtime/ros2_ws/src/agenticros_sim/launch/sim_arm.launch.py +223 -0
  27. package/runtime/ros2_ws/src/agenticros_sim/models/agenticros_amr/model.sdf +1 -1
  28. package/runtime/ros2_ws/src/agenticros_sim/models/agenticros_arm/model.config +26 -0
  29. package/runtime/ros2_ws/src/agenticros_sim/models/agenticros_arm/model.sdf +426 -0
  30. package/runtime/ros2_ws/src/agenticros_sim/urdf/agenticros_arm.urdf.xacro +205 -0
  31. package/runtime/ros2_ws/src/agenticros_sim/worlds/agenticros_indoor.sdf +1 -1
@@ -0,0 +1,173 @@
1
+ /**
2
+ * Mode profile storage for AgenticROS.
3
+ *
4
+ * Profiles live at ~/.agenticros/profiles/<mode>.json. The active profile is
5
+ * copied into ~/.agenticros/config.json (which is what every adapter actually
6
+ * reads). Swapping profiles is what `agenticros config use <mode>` (and the
7
+ * up-runners) does so users can flip between real-robot and simulation
8
+ * without hand-editing JSON.
9
+ *
10
+ * Why profiles instead of a single config: the real robot and the sim AMR
11
+ * have different namespaces, transports, safety limits, and camera topics.
12
+ * Tracking both in one file requires the MCP server to know "which mode is
13
+ * active right now," which is exactly the problem `.mcp.json` env override
14
+ * already tried to solve - badly, because env vars unconditionally win and
15
+ * silently break the other mode. With profiles + a live ~/.agenticros/
16
+ * config.json, everything reads from one place; the CLI just swaps it.
17
+ *
18
+ * Profile bootstrap policy:
19
+ * * On first use, if ~/.agenticros/config.json exists but no profiles do,
20
+ * we treat the current config as the user's last-used mode and seed
21
+ * profiles from defaults for both modes (preserving any namespace the
22
+ * user already had for whichever mode matches it).
23
+ * * Otherwise we write the canonical defaults below.
24
+ */
25
+ import { copyFileSync, existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
26
+ import { join } from "node:path";
27
+ import { getCliPaths } from "./paths.js";
28
+ export function profilesDir() {
29
+ return join(getCliPaths().userDataDir, "profiles");
30
+ }
31
+ export function profilePath(mode) {
32
+ return join(profilesDir(), `${mode}.json`);
33
+ }
34
+ export function activeConfigPath() {
35
+ return join(getCliPaths().userDataDir, "config.json");
36
+ }
37
+ export function modeMarkerPath() {
38
+ return join(getCliPaths().userDataDir, "active-mode");
39
+ }
40
+ export function readActiveMode() {
41
+ try {
42
+ const raw = readFileSync(modeMarkerPath(), "utf8").trim();
43
+ if (raw === "real" || raw === "sim")
44
+ return raw;
45
+ }
46
+ catch {
47
+ // No marker yet.
48
+ }
49
+ return null;
50
+ }
51
+ /**
52
+ * Canonical real-robot profile. The namespace is intentionally a placeholder
53
+ * - users edit it once after `init` (or `config set robot.namespace=...`) to
54
+ * match their robot. We DO NOT bake in the workspace's example UUID because
55
+ * that gets shared in repos.
56
+ */
57
+ function realProfileDefaults(namespaceFallback) {
58
+ return {
59
+ transport: { mode: "local" },
60
+ robot: {
61
+ namespace: namespaceFallback ?? "my_robot",
62
+ name: "Real Robot",
63
+ cameraTopic: "/camera/camera/color/image_raw",
64
+ },
65
+ safety: { maxLinearVelocity: 1.0, maxAngularVelocity: 1.5 },
66
+ teleop: { cmdVelTopic: "/cmd_vel", speedDefault: 0.3 },
67
+ };
68
+ }
69
+ /**
70
+ * Canonical sim-AMR profile. Mirrors ros2_ws/src/agenticros_sim/config/
71
+ * agenticros-sim.config.json - namespace MUST be empty because the sim
72
+ * bridge in amr_bridge.yaml publishes /cmd_vel, /odom, etc. at the graph
73
+ * root (no robot prefix). Setting a namespace here means Claude publishes
74
+ * into a void during simulation.
75
+ */
76
+ function simProfileDefaults() {
77
+ return {
78
+ transport: { mode: "local" },
79
+ robot: {
80
+ namespace: "",
81
+ name: "Sim AMR",
82
+ cameraTopic: "/camera/camera/color/image_raw",
83
+ },
84
+ safety: { maxLinearVelocity: 0.5, maxAngularVelocity: 1.0 },
85
+ teleop: { cmdVelTopic: "/cmd_vel", speedDefault: 0.2 },
86
+ skills: {
87
+ followme: { depthTopic: "/camera/camera/depth/image_rect_raw" },
88
+ },
89
+ };
90
+ }
91
+ function safeReadJson(p) {
92
+ try {
93
+ return JSON.parse(readFileSync(p, "utf8"));
94
+ }
95
+ catch {
96
+ return null;
97
+ }
98
+ }
99
+ /**
100
+ * Ensure both real and sim profile files exist. Returns true if anything was
101
+ * written (so callers can log it).
102
+ */
103
+ export function ensureProfilesExist() {
104
+ const dir = profilesDir();
105
+ mkdirSync(dir, { recursive: true });
106
+ let wrote = false;
107
+ const realPath = profilePath("real");
108
+ const simPath = profilePath("sim");
109
+ // Bootstrap: if a config.json already exists from before profiles existed,
110
+ // try to preserve whatever namespace the user had set. We don't know which
111
+ // mode that config represents, so we use the current namespace for the
112
+ // real-mode default (most users had a real-robot setup) and leave sim
113
+ // strictly empty.
114
+ let existingNs;
115
+ const active = activeConfigPath();
116
+ if (existsSync(active)) {
117
+ const cur = safeReadJson(active);
118
+ const ns = cur?.robot?.namespace;
119
+ if (typeof ns === "string" && ns.length > 0)
120
+ existingNs = ns;
121
+ }
122
+ if (!existsSync(realPath)) {
123
+ writeFileSync(realPath, JSON.stringify(realProfileDefaults(existingNs), null, 2) + "\n");
124
+ wrote = true;
125
+ }
126
+ if (!existsSync(simPath)) {
127
+ writeFileSync(simPath, JSON.stringify(simProfileDefaults(), null, 2) + "\n");
128
+ wrote = true;
129
+ }
130
+ return wrote;
131
+ }
132
+ /**
133
+ * Swap ~/.agenticros/config.json to the requested mode and persist the
134
+ * active-mode marker. Returns the absolute path to the active config.
135
+ *
136
+ * Idempotent: calling switchMode("sim") when sim is already active just
137
+ * re-copies the profile (cheap, ensures freshness).
138
+ */
139
+ export function switchMode(mode) {
140
+ ensureProfilesExist();
141
+ const src = profilePath(mode);
142
+ const dst = activeConfigPath();
143
+ mkdirSync(getCliPaths().userDataDir, { recursive: true });
144
+ copyFileSync(src, dst);
145
+ writeFileSync(modeMarkerPath(), mode + "\n");
146
+ return dst;
147
+ }
148
+ /**
149
+ * Mutate a single field inside the profile JSON (e.g. real.robot.namespace).
150
+ * Use sparingly - profiles are normally edited by hand or via `agenticros
151
+ * config set` against the active config.
152
+ */
153
+ export function patchProfile(mode, path, value) {
154
+ ensureProfilesExist();
155
+ const p = profilePath(mode);
156
+ const obj = safeReadJson(p) ?? {};
157
+ let cursor = obj;
158
+ for (let i = 0; i < path.length - 1; i++) {
159
+ const k = path[i];
160
+ const next = cursor[k];
161
+ if (next && typeof next === "object" && !Array.isArray(next)) {
162
+ cursor = next;
163
+ }
164
+ else {
165
+ const o = {};
166
+ cursor[k] = o;
167
+ cursor = o;
168
+ }
169
+ }
170
+ cursor[path[path.length - 1]] = value;
171
+ writeFileSync(p, JSON.stringify(obj, null, 2) + "\n");
172
+ }
173
+ //# sourceMappingURL=profiles.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"profiles.js","sourceRoot":"","sources":["../../src/util/profiles.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agenticros",
3
- "version": "0.1.8",
3
+ "version": "0.1.10",
4
4
  "type": "module",
5
5
  "description": "AgenticROS - agentic AI for ROS-powered robots. Single CLI to launch real-robot or simulated demos, manage configuration, and inspect status.",
6
6
  "keywords": [
@@ -1,5 +1,5 @@
1
1
  {
2
- "packedAt": "2026-06-05T23:06:49.989Z",
2
+ "packedAt": "2026-06-06T13:54:42.821Z",
3
3
  "repo": "https://github.com/PlaiPin/agenticros",
4
4
  "note": "This directory is a snapshot of the agenticros monorepo source. `agenticros init` will copy it to ~/agenticros and run pnpm install + colcon build there.",
5
5
  "layout": {
@@ -1,9 +1,9 @@
1
1
  # agenticros_sim
2
2
 
3
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.
4
+ a 2-wheel diff-drive AMR (depth camera + 2D lidar + IMU), a 6-DOF UR5e-shaped
5
+ robotic arm, and a `ros_gz_bridge` config that exposes everything on the topic
6
+ names the real-robot plugin already expects.
7
7
 
8
8
  ## What's inside
9
9
 
@@ -11,13 +11,20 @@ plugin already expects.
11
11
  agenticros_sim/
12
12
  ├── worlds/agenticros_indoor.sdf 12 x 12 m indoor room with obstacles
13
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
14
+ ├── models/
15
+ │ ├── agenticros_amr/ 2-wheel diff-drive AMR with sensors
16
+ │ └── agenticros_arm/ 6-DOF UR5e-shaped robotic arm
17
+ ├── urdf/
18
+ │ ├── agenticros_amr.urdf.xacro URDF mirror for RViz (AMR)
19
+ │ └── agenticros_arm.urdf.xacro URDF mirror for RViz (arm)
17
20
  ├── 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
+ │ ├── amr_bridge.yaml gz <-> ROS topic mapping (AMR)
22
+ ├── amr_view.rviz RViz config: camera, scan, TF
23
+ ├── arm_bridge.yaml gz <-> ROS topic mapping (arm)
24
+ │ └── arm_view.rviz RViz config: RobotModel + TF
25
+ ├── launch/
26
+ │ ├── sim_amr.launch.py One-stop launcher (AMR)
27
+ │ └── sim_arm.launch.py One-stop launcher (arm)
21
28
  ├── env-hooks/ Add the package's share/ to GZ_SIM_RESOURCE_PATH
22
29
  └── CMakeLists.txt + package.xml Standard ament_cmake skeleton
23
30
  ```
@@ -26,18 +33,50 @@ agenticros_sim/
26
33
 
27
34
  ```bash
28
35
  # 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)
36
+ agenticros up sim-amr # AMR: GUI
37
+ agenticros up sim-amr --rviz # AMR: GUI + RViz panel
38
+ agenticros up sim-arm # Arm: GUI
39
+ agenticros up sim-arm --rviz # Arm: GUI + RViz (RobotModel + TF)
32
40
 
33
- # Or run the launch file directly:
41
+ # Or run the launch files directly:
34
42
  cd ros2_ws && colcon build --symlink-install --packages-select agenticros_sim
35
43
  source install/setup.bash
36
44
  ros2 launch agenticros_sim sim_amr.launch.py
37
45
  ros2 launch agenticros_sim sim_amr.launch.py use_rviz:=true
38
46
  ros2 launch agenticros_sim sim_amr.launch.py gui:=false # headless
47
+ ros2 launch agenticros_sim sim_arm.launch.py
48
+ ros2 launch agenticros_sim sim_arm.launch.py use_rviz:=true
39
49
  ```
40
50
 
51
+ ## Arm topic layout
52
+
53
+ The arm exposes one position-command topic per joint plus the usual
54
+ `/joint_states`, `/tf`, and `/clock`. Send a target angle in radians as a
55
+ `std_msgs/Float64` and the PD controller drives the joint there.
56
+
57
+ | Topic | Type | Direction |
58
+ |------------------------------------|-------------------------------|-----------|
59
+ | `/arm/shoulder_pan/cmd_pos` | `std_msgs/msg/Float64` | ROS -> GZ |
60
+ | `/arm/shoulder_lift/cmd_pos` | `std_msgs/msg/Float64` | ROS -> GZ |
61
+ | `/arm/elbow/cmd_pos` | `std_msgs/msg/Float64` | ROS -> GZ |
62
+ | `/arm/wrist_1/cmd_pos` | `std_msgs/msg/Float64` | ROS -> GZ |
63
+ | `/arm/wrist_2/cmd_pos` | `std_msgs/msg/Float64` | ROS -> GZ |
64
+ | `/arm/wrist_3/cmd_pos` | `std_msgs/msg/Float64` | ROS -> GZ |
65
+ | `/joint_states` | `sensor_msgs/msg/JointState` | GZ -> ROS |
66
+ | `/tf`, `/tf_static` | `tf2_msgs/msg/TFMessage` | GZ -> ROS |
67
+ | `/clock` | `rosgraph_msgs/msg/Clock` | GZ -> ROS |
68
+
69
+ Example - wave the elbow back and forth from the command line:
70
+
71
+ ```bash
72
+ ros2 topic pub /arm/elbow/cmd_pos std_msgs/msg/Float64 'data: 1.0' --once
73
+ sleep 2
74
+ ros2 topic pub /arm/elbow/cmd_pos std_msgs/msg/Float64 'data: -0.5' --once
75
+ ```
76
+
77
+ The same via an MCP `ros2_publish` tool call from Claude / Codex / Gemini works
78
+ identically.
79
+
41
80
  ## Topic layout
42
81
 
43
82
  The bridge YAML deliberately matches the real-robot AgenticROS plugin's topic
@@ -0,0 +1,84 @@
1
+ # arm_bridge.yaml
2
+ #
3
+ # Bridge config for the 6-DOF agenticros_arm sim. Feeds ros_gz_bridge's
4
+ # parameter_bridge so Gazebo Harmonic topics produced by the arm's
5
+ # JointPositionController + JointStatePublisher + PosePublisher plugins
6
+ # are exposed as the ROS 2 topics agent code expects.
7
+ #
8
+ # Direction notation:
9
+ # GZ_TO_ROS — gazebo publishes, ROS subscribes (joint feedback, TF, clock)
10
+ # ROS_TO_GZ — ROS publishes, gazebo subscribes (joint commands)
11
+ # BIDIRECTIONAL — rarely needed
12
+ #
13
+ # Topic naming convention: /arm/<joint>/cmd_pos for joint commands. Same
14
+ # naming pattern across all six joints so a Claude / Codex / Gemini
15
+ # `ros2_publish` tool call only needs to vary the joint name.
16
+
17
+ # ---------------- Clock (GZ -> ROS) ----------------
18
+ - ros_topic_name: "/clock"
19
+ gz_topic_name: "/clock"
20
+ ros_type_name: "rosgraph_msgs/msg/Clock"
21
+ gz_type_name: "gz.msgs.Clock"
22
+ direction: GZ_TO_ROS
23
+
24
+ # ---------------- /tf (GZ -> ROS) ----------------
25
+ - ros_topic_name: "/tf"
26
+ gz_topic_name: "/model/agenticros_arm/pose"
27
+ ros_type_name: "tf2_msgs/msg/TFMessage"
28
+ gz_type_name: "gz.msgs.Pose_V"
29
+ direction: GZ_TO_ROS
30
+
31
+ - ros_topic_name: "/tf_static"
32
+ gz_topic_name: "/model/agenticros_arm/pose_static"
33
+ ros_type_name: "tf2_msgs/msg/TFMessage"
34
+ gz_type_name: "gz.msgs.Pose_V"
35
+ direction: GZ_TO_ROS
36
+
37
+ # ---------------- Joint feedback (GZ -> ROS) ----------------
38
+ # robot_state_publisher consumes this to update the URDF transforms in
39
+ # RViz and to publish per-link /tf entries. The gz topic name matches the
40
+ # <topic>joint_states</topic> field on the SDF's JointStatePublisher
41
+ # plugin (gz-sim treats that as the literal topic, no model prefix).
42
+ - ros_topic_name: "/joint_states"
43
+ gz_topic_name: "/joint_states"
44
+ ros_type_name: "sensor_msgs/msg/JointState"
45
+ gz_type_name: "gz.msgs.Model"
46
+ direction: GZ_TO_ROS
47
+
48
+ # ---------------- Joint position commands (ROS -> GZ) ----------------
49
+ # Send std_msgs/Float64 (radians) to any of these to drive a joint.
50
+ - ros_topic_name: "/arm/shoulder_pan/cmd_pos"
51
+ gz_topic_name: "/arm/shoulder_pan/cmd_pos"
52
+ ros_type_name: "std_msgs/msg/Float64"
53
+ gz_type_name: "gz.msgs.Double"
54
+ direction: ROS_TO_GZ
55
+
56
+ - ros_topic_name: "/arm/shoulder_lift/cmd_pos"
57
+ gz_topic_name: "/arm/shoulder_lift/cmd_pos"
58
+ ros_type_name: "std_msgs/msg/Float64"
59
+ gz_type_name: "gz.msgs.Double"
60
+ direction: ROS_TO_GZ
61
+
62
+ - ros_topic_name: "/arm/elbow/cmd_pos"
63
+ gz_topic_name: "/arm/elbow/cmd_pos"
64
+ ros_type_name: "std_msgs/msg/Float64"
65
+ gz_type_name: "gz.msgs.Double"
66
+ direction: ROS_TO_GZ
67
+
68
+ - ros_topic_name: "/arm/wrist_1/cmd_pos"
69
+ gz_topic_name: "/arm/wrist_1/cmd_pos"
70
+ ros_type_name: "std_msgs/msg/Float64"
71
+ gz_type_name: "gz.msgs.Double"
72
+ direction: ROS_TO_GZ
73
+
74
+ - ros_topic_name: "/arm/wrist_2/cmd_pos"
75
+ gz_topic_name: "/arm/wrist_2/cmd_pos"
76
+ ros_type_name: "std_msgs/msg/Float64"
77
+ gz_type_name: "gz.msgs.Double"
78
+ direction: ROS_TO_GZ
79
+
80
+ - ros_topic_name: "/arm/wrist_3/cmd_pos"
81
+ gz_topic_name: "/arm/wrist_3/cmd_pos"
82
+ ros_type_name: "std_msgs/msg/Float64"
83
+ gz_type_name: "gz.msgs.Double"
84
+ direction: ROS_TO_GZ
@@ -0,0 +1,109 @@
1
+ Panels:
2
+ - Class: rviz_common/Displays
3
+ Help Height: 0
4
+ Name: Displays
5
+ Property Tree Widget:
6
+ Expanded:
7
+ - /TF1
8
+ - /RobotModel1
9
+ Splitter Ratio: 0.5
10
+ Tree Height: 600
11
+ - Class: rviz_common/Views
12
+ Expanded:
13
+ - /Current View1
14
+ Name: Views
15
+ Splitter Ratio: 0.5
16
+ Visualization Manager:
17
+ Class: ""
18
+ Displays:
19
+ - Alpha: 0.5
20
+ Cell Size: 0.5
21
+ Class: rviz_default_plugins/Grid
22
+ Color: 160; 160; 164
23
+ Enabled: true
24
+ Line Style:
25
+ Line Width: 0.03
26
+ Value: Lines
27
+ Name: Grid
28
+ Normal Cell Count: 0
29
+ Offset:
30
+ X: 0
31
+ Y: 0
32
+ Z: 0
33
+ Plane: XY
34
+ Plane Cell Count: 12
35
+ Reference Frame: <Fixed Frame>
36
+ Value: true
37
+ - Class: rviz_default_plugins/TF
38
+ Enabled: true
39
+ Frame Timeout: 15
40
+ Frames:
41
+ All Enabled: true
42
+ Marker Scale: 0.15
43
+ Name: TF
44
+ Show Arrows: true
45
+ Show Axes: true
46
+ Show Names: true
47
+ Update Interval: 0
48
+ Value: true
49
+ - Alpha: 1
50
+ Class: rviz_default_plugins/RobotModel
51
+ Collision Enabled: false
52
+ Description File: ""
53
+ Description Source: Topic
54
+ Description Topic:
55
+ Depth: 5
56
+ Durability Policy: Volatile
57
+ History Policy: Keep Last
58
+ Reliability Policy: Reliable
59
+ Value: /robot_description
60
+ Enabled: true
61
+ Mass Properties:
62
+ Inertia: false
63
+ Mass: false
64
+ Name: RobotModel
65
+ TF Prefix: ""
66
+ Update Interval: 0
67
+ Value: true
68
+ Visual Enabled: true
69
+ Enabled: true
70
+ Global Options:
71
+ Background Color: 48; 48; 48
72
+ Fixed Frame: base_link
73
+ Frame Rate: 30
74
+ Name: root
75
+ Tools:
76
+ - Class: rviz_default_plugins/Interact
77
+ Hide Inactive Objects: true
78
+ - Class: rviz_default_plugins/MoveCamera
79
+ - Class: rviz_default_plugins/Select
80
+ - Class: rviz_default_plugins/FocusCamera
81
+ - Class: rviz_default_plugins/Measure
82
+ Line color: 128; 128; 0
83
+ Transformation:
84
+ Current:
85
+ Class: rviz_default_plugins/TF
86
+ Value: true
87
+ Views:
88
+ Current:
89
+ Class: rviz_default_plugins/Orbit
90
+ Distance: 2.5
91
+ Enable Stereo Rendering:
92
+ Stereo Eye Separation: 0.0599999987
93
+ Stereo Focal Distance: 1
94
+ Swap Stereo Eyes: false
95
+ Value: false
96
+ Focal Point:
97
+ X: 0.4
98
+ Y: 0
99
+ Z: 0.4
100
+ Focal Shape Fixed Size: true
101
+ Focal Shape Size: 0.05
102
+ Invert Z Axis: false
103
+ Name: Current View
104
+ Near Clip Distance: 0.01
105
+ Pitch: 0.35
106
+ Target Frame: base_link
107
+ Value: Orbit (rviz)
108
+ Yaw: 0.785
109
+ Saved: ~