Skip to content

Commit b39d9d9

Browse files
committed
docs: describe Nav2 observation demo
Signed-off-by: SamuelFoo <fooenzesamuel@gmail.com>
1 parent 89ed1d0 commit b39d9d9

3 files changed

Lines changed: 107 additions & 10 deletions

File tree

discourse/3-layered-global-occupancy-map.md

Lines changed: 63 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,9 @@
22

33
# Layered Global Map Observations
44

5-
This post describes the observation interface for contributing temporary map
6-
information to the next generation Open-RMF prototype.
5+
This post describes the implemented observation interface and demos for
6+
contributing temporary map information to the next generation Open-RMF
7+
prototype.
78

89
The goal is to let robots and perception systems publish what they currently
910
observe without tying them to a specific central map implementation. The first
@@ -19,15 +20,21 @@ observations, can be added later.
1920
same sensor snapshot
2021
* Clear-space patches have TTLs, just like obstacle patches
2122
* A source can reset its previous observations without using a TTL
22-
* Robot-mounted sources can include the robot pose at observation time
23+
* Robot-mounted sources include the observation-frame pose at observation time
24+
* The Rust map server composes a static occupancy grid and active observations
25+
into `/map`
26+
* The Nav2 demo converts scans from three robots into point regions and displays
27+
the combined map
2328
* The observation messages live in `rmf_layered_map_msgs`, leaving
2429
`rmf_prototype_msgs` unchanged
2530

26-
# Observation Topic
31+
# Observation Topics
2732

28-
Observation sources publish dynamic map observations on:
33+
The layered map server uses these topics:
2934

35+
* `/map/static` - static `nav_msgs/OccupancyGrid`
3036
* `/map/region_updates` - [`MapRegionUpdate.msg`](../rmf_layered_map_msgs/msg/MapRegionUpdate.msg)
37+
* `/map` - composed `nav_msgs/OccupancyGrid`
3138

3239
The topic is an event stream. Updates are not latched because expired
3340
observations should not be replayed to a restarted map service as if they were
@@ -105,6 +112,50 @@ sensor-local regions with their sensor pose, while synthetic sources whose
105112
regions are already global can use the identity pose. The first implementation
106113
accepts point and axis-aligned rectangle regions.
107114

115+
# Layered Map Server
116+
117+
`rmf_layered_map_server` keeps the static occupancy grid separate from dynamic
118+
observations and publishes their composition on `/map`. It validates source
119+
timestamps and frames, ignores updates that are older than the latest accepted
120+
update from the same source, supports source resets, and removes observations
121+
after their TTL expires.
122+
123+
The server applies clear patches before obstacle patches from the same update.
124+
During composition, obstacle observations win over clear observations so
125+
occupied space is not accidentally erased by another active source.
126+
127+
# Three-Robot Nav2 Demo
128+
129+
The committed Nav2 demo can be launched with:
130+
131+
```bash
132+
ros2 launch rmf_layered_map_server_demo nav2_observations.launch.py
133+
```
134+
135+
The launch file starts three stationary robots in different free corners of the
136+
warehouse and spawns one deterministic Gazebo box near each robot. Each
137+
observation node subscribes to its robot's local `sensor_msgs/LaserScan`,
138+
filters invalid or out-of-range returns, and publishes the remaining scan
139+
endpoints as point regions.
140+
141+
Each scan is a replacement snapshot: `reset_source` removes the source's
142+
preceding points before the new points are added, and a short TTL removes the
143+
source if it stops publishing. The observation-frame pose is recorded in the
144+
shared `map` frame so the map server can transform the scan-local regions before
145+
rasterizing them.
146+
147+
The demo launches Nav2 localization but does not launch Nav2 planning or control
148+
components, RMF planning, or navigation goals. Three robot-local RViz windows
149+
are enabled by default, and another RViz window displays the combined global
150+
`/map`.
151+
152+
The scan-to-region conversion is deliberately simple so its information loss
153+
and publication cost are visible. `beam_stride` reduces the number of point
154+
regions, `publish_period_sec` throttles replacement snapshots, and
155+
`max_observation_range` limits represented returns. The current demo publishes
156+
occupied endpoints only; it does not convert raycast clearing into free-space
157+
regions or compress adjacent points into larger regions.
158+
108159
# Example Flow
109160

110161
A local costmap or LiDAR observation node can publish a replacement snapshot by:
@@ -118,22 +169,24 @@ A local costmap or LiDAR observation node can publish a replacement snapshot by:
118169
5. Giving each patch a TTL long enough to survive normal publication jitter but
119170
short enough to decay when the observation is no longer refreshed.
120171

121-
The map service should ignore snapshots from a source if their timestamp is
122-
older than a newer snapshot that has already been accepted. This prevents a late
123-
clear/reset message from removing obstacle information that came from a newer
172+
The map server ignores snapshots from a source if their timestamp is older than
173+
a newer snapshot that has already been accepted. This prevents a late clear or
174+
reset message from removing obstacle information that came from a newer
124175
observation.
125176

126177
# Implemented Test Coverage
127178

128-
The first server tests cover:
179+
The committed server and demo tests cover:
129180

130181
* composing obstacle regions over a static planning grid
131182
* point regions with non-zero map origins and non-1.0 resolutions
132183
* transforming robot-local regions into the global map frame
133184
* out-of-bounds regions, malformed point arrays, and unsupported region types
134-
* rejecting updates without a timestamp
185+
* rejecting updates without a timestamp or in a different global frame
135186
* pruning expired observations by TTL
136187
* clear and obstacle patches in the same update
137188
* late older snapshots being ignored
138189
* reset updates removing observations from the same source and map
139190
* multiple robot sources being stitched into one composed grid
191+
* filtering invalid and out-of-range laser returns
192+
* preserving original beam angles when scan points are sampled

map_server/README.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,13 @@ ros2 launch rmf_layered_map_server_demo demo.launch.py
1111
```
1212

1313
Use `use_rviz:=False` for a headless run.
14+
15+
## Nav2 Observations
16+
17+
The three-robot demo converts local laser observations into point regions and combines them into the global `/map`. It launches three robots in warehouse corners, deterministic clutter for each robot to observe, the layered map server, and a separate RViz window for the combined map. It does not launch RMF or Nav2 planning components.
18+
19+
```bash
20+
ros2 launch rmf_layered_map_server_demo nav2_observations.launch.py
21+
```
22+
23+
See [`rmf_layered_map_server_demo/README.md`](rmf_layered_map_server_demo/README.md) for launch arguments and the current scan-to-region limitations.
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
# Layered Map Server Demos
2+
3+
This package contains two demonstrations of the layered map server.
4+
5+
## TTL Smoke Test
6+
7+
The small smoke test publishes a synthetic static grid and a temporary rectangle with a five-second TTL:
8+
9+
```bash
10+
ros2 launch rmf_layered_map_server_demo demo.launch.py
11+
```
12+
13+
## Three-Robot Nav2 Observation Demo
14+
15+
The Nav2 demo starts three stationary robots in free corners of the warehouse map and spawns one deterministic box near each robot. Each robot's observation node subscribes to its `sensor_msgs/LaserScan`, represents valid scan endpoints as point `Region` messages, and publishes a replacing `MapRegionUpdate` snapshot. The layered map server transforms and combines all three sources over the static map.
16+
17+
No RMF planning components or navigation goals are required. By default the Nav2 launch opens three robot-local RViz windows, and the demo opens another RViz window showing the combined `/map`:
18+
19+
```bash
20+
ros2 launch rmf_layered_map_server_demo nav2_observations.launch.py
21+
```
22+
23+
Use `use_nav2_rviz:=False` to open only the combined-map view. Use `spawn_clutter:=False` to run against the unmodified warehouse world.
24+
25+
The initial implementation deliberately keeps the scan-to-region conversion simple so its cost and information loss are visible. `beam_stride` samples fewer endpoints, `publish_period_sec` throttles snapshots, `max_observation_range` limits represented returns, and `ttl_sec` controls how quickly stale snapshots expire. For example:
26+
27+
```bash
28+
ros2 launch rmf_layered_map_server_demo nav2_observations.launch.py \
29+
beam_stride:=4 publish_period_sec:=1.0
30+
```
31+
32+
Each publisher logs the number of input beams and output regions. This makes it possible to compare message density and global-map update rate against the visual fidelity in RViz.
33+
34+
The prototype publishes occupied endpoints only. It does not yet turn clearing rays into free-space regions or compress adjacent endpoints into larger region primitives. `reset_source` removes the previous snapshot before each new scan, and TTL expiry removes observations if a robot stops publishing.

0 commit comments

Comments
 (0)