hello-robot-stretch4-nav-webapp 0.1.0__tar.gz

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 (70) hide show
  1. hello_robot_stretch4_nav_webapp-0.1.0/LICENSE.md +11 -0
  2. hello_robot_stretch4_nav_webapp-0.1.0/MANIFEST.in +13 -0
  3. hello_robot_stretch4_nav_webapp-0.1.0/PKG-INFO +365 -0
  4. hello_robot_stretch4_nav_webapp-0.1.0/README.md +349 -0
  5. hello_robot_stretch4_nav_webapp-0.1.0/frontend/index.html +12 -0
  6. hello_robot_stretch4_nav_webapp-0.1.0/frontend/package-lock.json +1844 -0
  7. hello_robot_stretch4_nav_webapp-0.1.0/frontend/package.json +22 -0
  8. hello_robot_stretch4_nav_webapp-0.1.0/frontend/src/App.jsx +270 -0
  9. hello_robot_stretch4_nav_webapp-0.1.0/frontend/src/api.js +23 -0
  10. hello_robot_stretch4_nav_webapp-0.1.0/frontend/src/components/ActionsMenu.jsx +299 -0
  11. hello_robot_stretch4_nav_webapp-0.1.0/frontend/src/components/CameraPanel.jsx +200 -0
  12. hello_robot_stretch4_nav_webapp-0.1.0/frontend/src/components/CanvasMapViewer.jsx +1001 -0
  13. hello_robot_stretch4_nav_webapp-0.1.0/frontend/src/components/ErrorBoundary.jsx +33 -0
  14. hello_robot_stretch4_nav_webapp-0.1.0/frontend/src/components/MapLayerEditor.jsx +540 -0
  15. hello_robot_stretch4_nav_webapp-0.1.0/frontend/src/components/MapShapePanel.jsx +255 -0
  16. hello_robot_stretch4_nav_webapp-0.1.0/frontend/src/components/MapViewer.jsx +762 -0
  17. hello_robot_stretch4_nav_webapp-0.1.0/frontend/src/components/PreflightScreen.jsx +346 -0
  18. hello_robot_stretch4_nav_webapp-0.1.0/frontend/src/components/RobotStatusPanel.jsx +181 -0
  19. hello_robot_stretch4_nav_webapp-0.1.0/frontend/src/components/RunstopBanner.jsx +32 -0
  20. hello_robot_stretch4_nav_webapp-0.1.0/frontend/src/components/RunstopButton.jsx +50 -0
  21. hello_robot_stretch4_nav_webapp-0.1.0/frontend/src/components/SemanticRegionBar.jsx +151 -0
  22. hello_robot_stretch4_nav_webapp-0.1.0/frontend/src/hooks/useRobotReadiness.js +49 -0
  23. hello_robot_stretch4_nav_webapp-0.1.0/frontend/src/hooks/useRosTopic.js +190 -0
  24. hello_robot_stretch4_nav_webapp-0.1.0/frontend/src/hooks/useRunstop.js +39 -0
  25. hello_robot_stretch4_nav_webapp-0.1.0/frontend/src/hooks/useUrdfRobot.js +119 -0
  26. hello_robot_stretch4_nav_webapp-0.1.0/frontend/src/index.css +2230 -0
  27. hello_robot_stretch4_nav_webapp-0.1.0/frontend/src/main.jsx +10 -0
  28. hello_robot_stretch4_nav_webapp-0.1.0/frontend/src/pages/EditMapPage.jsx +556 -0
  29. hello_robot_stretch4_nav_webapp-0.1.0/frontend/src/pages/MappingPage.jsx +299 -0
  30. hello_robot_stretch4_nav_webapp-0.1.0/frontend/src/pages/NavigationPage.jsx +1128 -0
  31. hello_robot_stretch4_nav_webapp-0.1.0/frontend/src/ros/rosConnectionManager.js +70 -0
  32. hello_robot_stretch4_nav_webapp-0.1.0/frontend/src/utils/rasterizeShapes.js +72 -0
  33. hello_robot_stretch4_nav_webapp-0.1.0/frontend/src/utils/tf.js +138 -0
  34. hello_robot_stretch4_nav_webapp-0.1.0/frontend/vite.config.js +20 -0
  35. hello_robot_stretch4_nav_webapp-0.1.0/hello_robot_stretch4_nav_webapp.egg-info/PKG-INFO +365 -0
  36. hello_robot_stretch4_nav_webapp-0.1.0/hello_robot_stretch4_nav_webapp.egg-info/SOURCES.txt +68 -0
  37. hello_robot_stretch4_nav_webapp-0.1.0/hello_robot_stretch4_nav_webapp.egg-info/dependency_links.txt +1 -0
  38. hello_robot_stretch4_nav_webapp-0.1.0/hello_robot_stretch4_nav_webapp.egg-info/entry_points.txt +2 -0
  39. hello_robot_stretch4_nav_webapp-0.1.0/hello_robot_stretch4_nav_webapp.egg-info/requires.txt +6 -0
  40. hello_robot_stretch4_nav_webapp-0.1.0/hello_robot_stretch4_nav_webapp.egg-info/top_level.txt +1 -0
  41. hello_robot_stretch4_nav_webapp-0.1.0/pyproject.toml +31 -0
  42. hello_robot_stretch4_nav_webapp-0.1.0/setup.cfg +4 -0
  43. hello_robot_stretch4_nav_webapp-0.1.0/stretch4_nav_webapp/__init__.py +1 -0
  44. hello_robot_stretch4_nav_webapp-0.1.0/stretch4_nav_webapp/app.py +670 -0
  45. hello_robot_stretch4_nav_webapp-0.1.0/stretch4_nav_webapp/cli.py +351 -0
  46. hello_robot_stretch4_nav_webapp-0.1.0/stretch4_nav_webapp/config/default.yaml +30 -0
  47. hello_robot_stretch4_nav_webapp-0.1.0/stretch4_nav_webapp/map_transform.py +308 -0
  48. hello_robot_stretch4_nav_webapp-0.1.0/stretch4_nav_webapp/maps_api.py +584 -0
  49. hello_robot_stretch4_nav_webapp-0.1.0/stretch4_nav_webapp/modes/__init__.py +8 -0
  50. hello_robot_stretch4_nav_webapp-0.1.0/stretch4_nav_webapp/modes/base.py +75 -0
  51. hello_robot_stretch4_nav_webapp-0.1.0/stretch4_nav_webapp/modes/edit_map.py +20 -0
  52. hello_robot_stretch4_nav_webapp-0.1.0/stretch4_nav_webapp/modes/mapping.py +67 -0
  53. hello_robot_stretch4_nav_webapp-0.1.0/stretch4_nav_webapp/modes/navigation.py +97 -0
  54. hello_robot_stretch4_nav_webapp-0.1.0/stretch4_nav_webapp/nav_actions.py +298 -0
  55. hello_robot_stretch4_nav_webapp-0.1.0/stretch4_nav_webapp/paths.py +52 -0
  56. hello_robot_stretch4_nav_webapp-0.1.0/stretch4_nav_webapp/process_manager.py +208 -0
  57. hello_robot_stretch4_nav_webapp-0.1.0/stretch4_nav_webapp/robot_assets.py +123 -0
  58. hello_robot_stretch4_nav_webapp-0.1.0/stretch4_nav_webapp/robot_client_helper.py +257 -0
  59. hello_robot_stretch4_nav_webapp-0.1.0/stretch4_nav_webapp/robot_status.py +394 -0
  60. hello_robot_stretch4_nav_webapp-0.1.0/stretch4_nav_webapp/static/assets/index-CCE1QALe.js +4169 -0
  61. hello_robot_stretch4_nav_webapp-0.1.0/stretch4_nav_webapp/static/assets/index-QtAzEarW.css +1 -0
  62. hello_robot_stretch4_nav_webapp-0.1.0/stretch4_nav_webapp/static/index.html +13 -0
  63. hello_robot_stretch4_nav_webapp-0.1.0/stretch4_nav_webapp/tests/__init__.py +0 -0
  64. hello_robot_stretch4_nav_webapp-0.1.0/stretch4_nav_webapp/tests/test_map_transform.py +275 -0
  65. hello_robot_stretch4_nav_webapp-0.1.0/stretch4_nav_webapp/tests/test_maps_api.py +257 -0
  66. hello_robot_stretch4_nav_webapp-0.1.0/stretch4_nav_webapp/tests/test_navigation_command.py +77 -0
  67. hello_robot_stretch4_nav_webapp-0.1.0/stretch4_nav_webapp/tests/test_readiness_gate.py +122 -0
  68. hello_robot_stretch4_nav_webapp-0.1.0/stretch4_nav_webapp/tests/test_robot_status.py +275 -0
  69. hello_robot_stretch4_nav_webapp-0.1.0/stretch4_nav_webapp/tests/test_save_map.py +77 -0
  70. hello_robot_stretch4_nav_webapp-0.1.0/stretch4_nav_webapp/tests/test_semantic_and_speed.py +206 -0
@@ -0,0 +1,11 @@
1
+ The following license applies to the entire contents of this directory (the "Contents"), which contains software for use with the Stretch mobile manipulators, which are robots produced and sold by Hello Robot Inc.
2
+
3
+ Copyright 2020-2026 Hello Robot Inc.
4
+
5
+ The Contents are licensed under the Apache License, Version 2.0 (the "License"). You may not use the Contents except in compliance with the License. You may obtain a copy of the License at
6
+
7
+ http://www.apache.org/licenses/LICENSE-2.0
8
+
9
+ Unless required by applicable law or agreed to in writing, the Contents are distributed under the License are distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
10
+
11
+ For further information about the Contents including inquiries about dual licensing, please contact Hello Robot Inc.
@@ -0,0 +1,13 @@
1
+ include README.md
2
+ recursive-include stretch4_nav_webapp/config *.yaml
3
+
4
+ # The built UI. It is gitignored but must be in both the wheel and the sdist,
5
+ # so that installing from either one needs no node.
6
+ recursive-include stretch4_nav_webapp/static *
7
+
8
+ # Frontend sources, so an sdist is a complete source release.
9
+ include frontend/index.html frontend/package.json frontend/package-lock.json frontend/vite.config.js
10
+ recursive-include frontend/src *
11
+ prune frontend/node_modules
12
+
13
+ global-exclude __pycache__ *.py[cod] .DS_Store
@@ -0,0 +1,365 @@
1
+ Metadata-Version: 2.4
2
+ Name: hello-robot-stretch4-nav-webapp
3
+ Version: 0.1.0
4
+ Summary: Stretch mapping, map editing, and navigation web UI
5
+ License-Expression: Apache-2.0
6
+ Requires-Python: >=3.10
7
+ Description-Content-Type: text/markdown
8
+ License-File: LICENSE.md
9
+ Requires-Dist: fastapi>=0.110
10
+ Requires-Dist: uvicorn[standard]>=0.27
11
+ Requires-Dist: pydantic>=2.0
12
+ Requires-Dist: pyyaml>=6.0
13
+ Requires-Dist: httpx>=0.27
14
+ Requires-Dist: pillow>=10.0
15
+ Dynamic: license-file
16
+
17
+ # Stretch4 Nav Webapp
18
+
19
+ Standalone web UI for Stretch 4 **mapping**, **map editing** (occupancy / keepout /
20
+ speed zones / named rooms, plus crop & rotate), and **navigation**. The app runs on the robot, you can open it from any browser on the same network.
21
+
22
+ ---
23
+
24
+ ## Requirements
25
+
26
+ | Need | Check it with |
27
+ |---|---|
28
+ | ROS 2 Jazzy with `stretch_nav2` built | `ros2 pkg list \| grep stretch_nav2` |
29
+ | `rosbridge_suite` | `ros2 pkg list \| grep rosbridge` |
30
+ | Python 3.10+ | `python3 --version` |
31
+
32
+ If `rosbridge_suite` is missing:
33
+
34
+ ```bash
35
+ sudo apt install ros-jazzy-rosbridge-server
36
+ ```
37
+
38
+ ---
39
+
40
+ ## Install
41
+
42
+ ```bash
43
+ pip3 install --user hello-robot-stretch4-nav-webapp
44
+ ```
45
+
46
+ The web UI ships prebuilt inside the package.
47
+
48
+ > **Use `--user`, not a virtualenv.** The app needs `rclpy` — which comes
49
+ > from the robot's ROS install, never from pip. A `--user` install
50
+ > lives in the robot's system Python and can see it.
51
+ ### Run it
52
+
53
+ ```bash
54
+ stretch4-nav-webapp
55
+ ```
56
+
57
+ Then open **http://\<robot-ip\>:8080** from any browser on the same network
58
+ (`hostname -I` on the robot gives you the IP).
59
+
60
+ That single command starts the API, serves the UI, and launches rosbridge.
61
+ Everything else — mapping, navigation, the camera — is started from buttons in
62
+ the UI.
63
+
64
+ ### Updating later
65
+
66
+ ```bash
67
+ pip3 install --user --upgrade hello-robot-stretch4-nav-webapp
68
+ # then restart stretch4-nav-webapp
69
+ ```
70
+
71
+ To run the code from a git checkout instead, see [Developing](#developing).
72
+
73
+ ---
74
+
75
+ ## CLI flags
76
+
77
+ ```bash
78
+ stretch4-nav-webapp # normal: UI on :8080, rosbridge on :9090
79
+ stretch4-nav-webapp --port 9000 # serve the UI on a different port
80
+ stretch4-nav-webapp --rosbridge-port 9091 # move rosbridge
81
+ stretch4-nav-webapp --maps-dir ~/my_maps # use a different maps folder
82
+ stretch4-nav-webapp --config ~/my_config.yaml # use a different config file entirely
83
+ stretch4-nav-webapp --print-config-path # where the default config lives, then exit
84
+ stretch4-nav-webapp --no-rosbridge # you already run rosbridge yourself
85
+ stretch4-nav-webapp --host 127.0.0.1 # local-only, no network access
86
+
87
+ # Skip the UI and start a mode immediately:
88
+ stretch4-nav-webapp --mapping
89
+ stretch4-nav-webapp --navigation my_map_name
90
+ stretch4-nav-webapp --edit_map my_map_name
91
+ ```
92
+
93
+ Flags always win over the config file.
94
+
95
+ ---
96
+
97
+ ## Configuration
98
+
99
+ One YAML file holds everything worth editing. Every setting below is safe to
100
+ change; the app re-reads it on restart.
101
+
102
+ ### Ports and paths
103
+
104
+ ```yaml
105
+ ui_port: 8080 # where the web UI is served
106
+ rosbridge_port: 9090 # the WebSocket the browser subscribes to ROS through
107
+ maps_dir: null # null = $HELLO_FLEET_PATH/maps, else ~/stretch_user/maps
108
+ host: "0.0.0.0" # 0.0.0.0 = reachable from other machines; 127.0.0.1 = robot only
109
+ ```
110
+
111
+ - **Change `ui_port`** if something else already owns 8080. The browser URL
112
+ changes with it; nothing else does.
113
+ - **Change `maps_dir`** to point at a different map library, e.g.
114
+ `maps_dir: "/home/hello-robot/shared_maps"`. The folder is created if missing.
115
+ - **Leave `host` at `0.0.0.0`** unless you specifically want the UI unreachable
116
+ from other machines.
117
+
118
+ ### Launch commands
119
+
120
+ These are the exact `ros2 launch` commands the mode buttons run. The `{braces}`
121
+ are filled in by the app before it runs them.
122
+
123
+ ```yaml
124
+ launches:
125
+ mapping: "ros2 launch stretch_nav2 offline_mapping.launch.py use_rviz:={use_rviz}"
126
+ navigation: "ros2 launch stretch_nav2 navigation_mppi.launch.py map:={map_yaml} use_rviz:={use_rviz}"
127
+ navigation_filters: "ros2 launch stretch_nav2 navigation_mppi_keepout.launch.py map:={map_yaml} keepout_mask:={keepout_yaml} speed_mask:={speed_yaml} enable_keepout:={enable_keepout} enable_speed:={enable_speed} use_rviz:={use_rviz}"
128
+ rosbridge: "ros2 run rosbridge_server rosbridge_websocket --ros-args -p port:={rosbridge_port} ..."
129
+
130
+ use_rviz: "false" # set "true" to also open RViz alongside the web UI
131
+ ```
132
+
133
+ ### Using your own config file
134
+
135
+ The default config lives inside the installed package. Copy it out, edit the
136
+ copy, and point the app at it — that way an upgrade never overwrites your
137
+ changes:
138
+
139
+ ```bash
140
+ cp "$(stretch4-nav-webapp --print-config-path)" ~/my_config.yaml
141
+ # edit ~/my_config.yaml
142
+ stretch4-nav-webapp --config ~/my_config.yaml
143
+ ```
144
+
145
+ ---
146
+
147
+ ## Modes
148
+
149
+ | Button | What it starts | What you see |
150
+ |--------|----------------|--------------|
151
+ | **Mapping** | `stretch_nav2 offline_mapping.launch.py` | Live map building as you drive with the gamepad |
152
+ | **Edit Map** | Nothing on the robot — file editing only | Paint tools for occupancy / keepout / speed / semantic / binary filter, plus crop & rotate |
153
+ | **Navigation** | Nav2 MPPI (+ keepout/speed filters if enabled) | Map, robot, lidar, costmaps, planned path, footprint |
154
+
155
+ Only **one mode runs at a time** — starting one stops the previous one.
156
+
157
+ Both robot viewers are top-down and mirror the stock Stretch RViz displays. The **Layers** checkboxes hide overlays without stopping the data.
158
+
159
+ ---
160
+
161
+ ## Where maps live
162
+
163
+ Under `$HELLO_FLEET_PATH/maps` (fallback `~/stretch_user/maps`), one folder per map:
164
+
165
+ ```
166
+ maps/<map_name>/
167
+ map.pgm + map.yaml The occupancy map itself
168
+ keepout.pgm + keepout.yaml No-go zones (black = blocked)
169
+ speed.pgm + speed.yaml Slow zones (darker = slower)
170
+ semantic.png + semantic.yaml Which room each cell belongs to
171
+ semantic.json The room names and colours
172
+ binary_filter_mask.pgm + .yaml Areas for a binary filter you launch yourself
173
+ locations.json Saved places you can send the robot to
174
+ .before_transform/ One undo step for crop & rotate
175
+ ```
176
+
177
+ ---
178
+
179
+ ## Keepout, speed & rooms
180
+
181
+ Edit Map paints four kinds of zone onto a saved map:
182
+
183
+ - **Keepout** — the robot will not enter, at all.
184
+ - **Speed** — the robot slows down; darker paint = slower.
185
+ - **Rooms** — you name an area ("Kitchen") and paint where it is.
186
+ - **Binary filter** — areas for a binary filter you launch yourself. Drawn here,
187
+ never launched here.
188
+
189
+ Switch keepout and speed on when you start Navigation. That's when the app picks
190
+ the `navigation_filters` launch instead of the plain one. See the
191
+ [Nav2 keepout tutorial](https://docs.nav2.org/tutorials/docs/navigation2_with_keepout_filter.html)
192
+ for what Nav2 does with them.
193
+
194
+ ### Binary filter (draw here, launch yourself)
195
+
196
+ There is a fourth mask, **Binary filter**, and it is deliberately different: the
197
+ app only *draws* it. Navigation from the app has no binary switch and never starts a filter
198
+ for it, because a binary filter is only half a feature, the other half is the
199
+ node you write that reacts to `/binary_state` (turn something on, play a sound,
200
+ stop the arm). What should happen in a marked area is yours to define.
201
+
202
+ What the app writes:
203
+
204
+ ```
205
+ maps/<map_name>/binary_filter_mask.pgm 255 everywhere, 153 where you painted
206
+ maps/<map_name>/binary_filter_mask.yaml mode: scale, free_thresh 0.0, occupied_thresh 1.0
207
+ ```
208
+
209
+ Point your own `filter_mask_server` at that yaml. With the usual
210
+ `base: 0.0`, `multiplier: 1.0`, `flip_threshold: 10.0`, any pixel darker than
211
+ about 229 flips the state, 153 is the grey used in the app.
212
+
213
+ It is cropped and rotated along with every other layer, so it stays registered
214
+ against the map.
215
+
216
+ ### What the speed percentage means
217
+
218
+ The slider is the share of full speed the robot **keeps**: 80% means it drives at
219
+ 80% of its normal speed there. That holds as long as the robot's speed filter is
220
+ configured `base: 100.0`, `multiplier: -1.0` (in `stretch_nav2`'s
221
+ `nav2_filter_servers.yaml`).
222
+
223
+ The slider stops at 5%, not 0%. Nav2 reads a speed limit of exactly zero as *"no
224
+ limit"*, so a pure-black speed zone would make the robot drive at **full** speed
225
+ through it. To forbid an area outright, paint it on the keepout layer instead.
226
+
227
+ ---
228
+
229
+ ## Crop & rotate
230
+
231
+ **Edit Map → Crop & rotate** (available on the Occupancy layer) reshapes the
232
+ whole map. It is not a paint tool:
233
+
234
+ - **Keep inside** trims the map to the selection; **Remove inside** clears the
235
+ selection back to blank (unknown / no-restriction) and keeps the map size.
236
+ - Rotation previews live on the canvas; nothing is written until Apply.
237
+ - Every layer — occupancy, keepout, speed, rooms, binary — is transformed
238
+ together, so the masks stay registered against the map.
239
+ - Saved locations are moved to match, so a location on the kitchen door is still
240
+ on the kitchen door afterwards.
241
+ - One undo step is kept, in `.before_transform/`.
242
+
243
+ ---
244
+
245
+ ## Developing
246
+
247
+ For changing the code rather than just running it. Needs Node 18+
248
+ (`node --version`) on top of the requirements above, because here you build the
249
+ UI yourself instead of getting it prebuilt from PyPI.
250
+
251
+ ```bash
252
+ git clone https://github.com/hello-robot/stretch4_nav_webapp
253
+ cd stretch4_nav_webapp
254
+
255
+ pip3 install --user -e . # editable: runs the clone in place
256
+
257
+ cd frontend
258
+ npm install
259
+ npm run build # writes stretch4_nav_webapp/static
260
+ cd ..
261
+
262
+ stretch4-nav-webapp
263
+ ```
264
+
265
+ > **The UI is served from `stretch4_nav_webapp/static`, not from
266
+ > `frontend/src`.** If you change anything under `frontend/src` and skip
267
+ > `npm run build`, the browser keeps showing the old version.
268
+
269
+ Tests:
270
+
271
+ ```bash
272
+ python3 -m pytest
273
+ ```
274
+
275
+ ---
276
+
277
+ ## Adding a new mode
278
+
279
+ 1. Create `stretch4_nav_webapp/modes/my_mode.py`:
280
+
281
+ ```python
282
+ from stretch4_nav_webapp.modes.base import Mode, ModeContext, register, shlex_split_launch
283
+
284
+ @register
285
+ class MyMode(Mode):
286
+ id = "my_mode"
287
+ label = "My Mode"
288
+ description = "Does something useful."
289
+ needs_robot = True
290
+
291
+ def start(self, ctx: ModeContext, **kwargs) -> dict:
292
+ cmd = shlex_split_launch("ros2 launch my_pkg my.launch.py")
293
+ ctx.process_manager.set_active_mode(self.id, cmd)
294
+ return {"ok": True, "mode": self.id, "command": cmd}
295
+ ```
296
+
297
+ 2. Import it from `stretch4_nav_webapp/modes/__init__.py` so it registers itself.
298
+ 3. Add a page and a button in `frontend/src/App.jsx` that calls
299
+ `api('/api/modes/my_mode/start', { method: 'POST', body: '{}' })`.
300
+ 4. Rebuild the frontend and restart `stretch4-nav-webapp`. The mode also shows up in
301
+ `GET /api/modes`.
302
+
303
+ ---
304
+
305
+ ## API
306
+
307
+ The same endpoints the UI buttons use.
308
+
309
+ **Modes**
310
+ - `GET /api/status` — active mode, ports, maps folder, process table
311
+ - `POST /api/modes/{mapping|navigation|edit_map}/start` — accepts
312
+ `{"map_name": "...", "use_keepout": true, "use_speed": true}` and
313
+ `{"skip_readiness": true}` to bypass the homed/stowed/dongle guardrail
314
+ - `POST /api/modes/stop`
315
+
316
+ **Robot**
317
+ - `GET /api/robot/readiness` — homed, stowed, battery, runstop, dongle, in-flight action
318
+ - `POST /api/robot/home` · `POST /api/robot/stow` — start the routine, returns immediately
319
+ - `POST /api/robot/runstop` `{"engaged": true|false}` — the safety stop
320
+ - `POST /api/robot/gamepad/start`
321
+
322
+ **Navigation**
323
+ - `POST /api/navigation/goal` `{"x":…, "y":…, "yaw":…}`
324
+ - `POST /api/navigation/cancel`
325
+ - `POST /api/navigation/initial_pose` — tell the robot where it is
326
+ - `POST /api/navigation/undock`
327
+
328
+ **Maps**
329
+ - `POST /api/mapping/save` `{"name": "..."}`
330
+ - `GET /api/maps`
331
+ - `GET|POST /api/maps/{name}/layer/{occupancy|keepout|speed|semantic|binary}`
332
+ - `GET|PUT /api/maps/{name}/locations`
333
+ - `GET|PUT /api/maps/{name}/semantic` — room names/colours
334
+ - `GET|POST /api/maps/{name}/transform` · `POST /api/maps/{name}/transform/undo`
335
+
336
+ **Camera**
337
+ - `GET /api/camera/status` · `POST /api/camera/start` · `POST /api/camera/stop`
338
+
339
+ ---
340
+
341
+ ## Troubleshooting
342
+
343
+ | Symptom | Cause |
344
+ |---|---|
345
+ | UI loads, robot never moves | Runstop engaged — the banner over the map has a Release button |
346
+ | Mode starts but the map stays empty | Give it ~30 s. If the Driver/Lidar chips go red, stop and restart the mode |
347
+ | Robot shown in the wrong place | Use **Set pose** to tell it where it actually is |
348
+ | Your UI change didn't appear | Working from source and `npm run build` wasn't run |
349
+ | `Address already in use` | Something else owns 8080 — use `--port` or change `ui_port` |
350
+ | Camera panel stuck on "Waiting for video" | Normal for 20–30 s. Longer means the driver failed — check `/tmp/stretch4_nav_webapp_camera.log` |
351
+
352
+
353
+ Every process the app starts writes its output to `/tmp/`:
354
+
355
+ ```
356
+ /tmp/stretch4_nav_webapp_mode_navigation.log
357
+ /tmp/stretch4_nav_webapp_mode_mapping.log
358
+ /tmp/stretch4_nav_webapp_rosbridge.log
359
+ /tmp/stretch4_nav_webapp_camera.log
360
+ /tmp/stretch4_nav_webapp_gamepad.log
361
+ /tmp/stretch4_nav_webapp_body_server.log
362
+ ```
363
+
364
+ That's the first place to look when something won't start — it holds the real
365
+ `ros2 launch` output, errors included.