diff --git a/content/learning-paths/cross-platform/tuning-zenoh-ros2-lp3/1-overview.md b/content/learning-paths/cross-platform/tuning-zenoh-ros2-lp3/1-overview.md new file mode 100644 index 0000000000..de683cccf0 --- /dev/null +++ b/content/learning-paths/cross-platform/tuning-zenoh-ros2-lp3/1-overview.md @@ -0,0 +1,31 @@ +--- +title: Overview +weight: 2 + +layout: learningpathall +--- + + +## Overview + +A robot can work correctly in a controlled test environment and still fail when you move its ROS 2 traffic over to Wi-Fi. This is sometimes described as a robot that *works on the bench*. + +The simulation from the preceding Learning Paths published three sensor streams: + +| Topic | What it contains | Approximate source traffic | +|---|---|---:| +| `/scan` | A two-dimensional laser scan | 0.4 Mbps | +| `/camera/image_raw` | Camera images | 85 Mbps | +| `/camera/points` | A three-dimensional [point cloud](https://en.wikipedia.org/wiki/Point_cloud) | 700 Mbps | + +These three streams together need about 800 Mbps, whereas a typical 2.4 GHz Wi-Fi connection might deliver only 50–100 Mbps of usable throughput. The sender can therefore produce between 8 and 16 times more data than the link can carry. + +This Learning Path tests four ways to control this traffic: compression, access control, downsampling, and quality of service (QoS) with congestion control. Most policies are applied at the Zenoh router. Compression must be enabled at both ends of the connection. + +The work is done in two series: +- Experiment A uses `tc`/`netem` to emulate a degraded wireless link between two containers on the same server, which isolates each mechanism under repeatable conditions. +- Experiment B repeats the measurements with a Raspberry Pi over real Wi-Fi, confirming the conclusions outside the emulator. + +## What you've learned and what's next + +The ROS 2 applications are not the problem in this experiment. The combined sensor traffic exceeds the capacity of the wireless link. Next, you'll start the completed LP1 and LP2 environment and record an unconstrained baseline. diff --git a/content/learning-paths/cross-platform/tuning-zenoh-ros2-lp3/2-setup-and-measure-the-baseline.md b/content/learning-paths/cross-platform/tuning-zenoh-ros2-lp3/2-setup-and-measure-the-baseline.md new file mode 100644 index 0000000000..20b6227880 --- /dev/null +++ b/content/learning-paths/cross-platform/tuning-zenoh-ros2-lp3/2-setup-and-measure-the-baseline.md @@ -0,0 +1,116 @@ +--- +title: Prepare the system and measure the baseline +weight: 3 + +layout: learningpathall +--- + +## Setup + +{{% notice Important %}} +Complete [Build a ROS 2 and Zenoh simulation environment on an Arm server](/learning-paths/cross-platform/ros2-zenoh-arm/) and [Distribute a ROS 2 robotic system across Arm devices with Zenoh](/learning-paths/cross-platform/distributed-ros2-zenoh-lp2/) before you continue. This Learning Path tunes that working system; it does not repeat its installation and network configuration. +{{% /notice %}} + +If the containers are stopped, start them from the Arm server host. Use the LP1 working directory if you selected a different location: + +```bash +cd ~/ros_zenoh +docker compose up -d +docker compose ps +``` + +Both services should report `Up`: + +```output +NAME STATUS +ros_zenoh-control-1 Up +ros_zenoh-robot-1 Up +``` + +The commands that ran in interactive terminals from the previous Learning Paths do not restart with the containers. If the robot stack is not running, expand the following section. + +
+Restart the robot stack + +Open the robot container desktop. +Run the router in the first terminal: + +```bash +source ~/workshop_env.bash +just router +``` + +Run the simulation in the second terminal: + +```bash +source ~/workshop_env.bash +just rox_simu no_gui +``` + +Run Navigation2 in the third terminal: + +```bash +source ~/workshop_env.bash +just rox_nav2 +``` + +
+ +Open another `robot` terminal and remove any network limit left by an earlier test: + +```bash +source ~/workshop_env.bash +just network_normal +``` + +## Understand the four measurements + +Throughout this Learning Path, you will repeat the same measurements after every configuration change. Run all four at the same time so that every scenario creates the same network demand. + +Using three separate terminals in the `control` container, run the following commands: + +| Terminal | Command | Value to record | +|---|---|---| +| Control 1 | `ros2 topic hz /scan` | Average rate and standard deviation | +| Control 2 | `ros2 topic hz /camera/image_raw` | Average rate and standard deviation | +| Control 3 | `ros2 topic bw /camera/points` | Average bandwidth and message size | + +Run the fourth measurement in a `robot` terminal: + +```bash +just iftop_router +``` + +This command monitors traffic leaving the Zenoh router on TCP port `7447`. Each remote `ros2 topic` process creates a separate connection, so you should see three active connections. + +At the end of the display, `iftop` reports three TX rates: + +```output +TX: rates: 813Mb 819Mb 832Mb +``` + +This shows the 2 s / 10 s / 40 s moving averages of traffic respectively sent by the robot. Record the **middle** value. + +![iftop display monitoring Zenoh router traffic. A red circle marks 819 Mb in the middle TX column, the 10-second average to record as the link traffic.#center](a0-iftop-baseline.png "The circled middle TX value is the 10-second link rate") + +{{% notice Note %}} +`iftop` reports bits per second, such as `819 Mbps`. `ros2 topic bw` reports bytes per second, such as `92 MB/s`. One byte contains 8 bits. +{{% /notice %}} + +## Record the baseline (A0) + +Let all four measurements run for 60–90 seconds, then complete the A0 row: + +**Expected result:** + +| Scenario | `/scan` | `/camera/image_raw` | `/camera/points` | Link traffic | +|---|---|---|---|---| +| A0: Baseline | 7.97 Hz (std 0.115 s) | 11.85 Hz (std 0.035 s) | ~88 MB/s (7.37 MB per frame) | ~810 Mbps | + +A typical baseline is approximately 8 Hz for `/scan`, 12 Hz for the image, 88–98 MB/s for the point cloud, and 800–820 Mbps of link traffic. Treat these as reference observations, not pass or fail limits. Simulation speed and host performance affect the exact values. + +Stop all four measurement commands with **Ctrl+C**. ROS 2 calculates these statistics cumulatively, so you must stop and restart the commands for each scenario. + +## What you've accomplished and what's next + +You've measured what reaches the remote receiver when the Docker link has enough capacity. This A0 row is the reference for every later result. Next, you'll constrain the link and observe which topics survive. diff --git a/content/learning-paths/cross-platform/tuning-zenoh-ros2-lp3/3-emulate-a-wireless-link.md b/content/learning-paths/cross-platform/tuning-zenoh-ros2-lp3/3-emulate-a-wireless-link.md new file mode 100644 index 0000000000..dbaa71025c --- /dev/null +++ b/content/learning-paths/cross-platform/tuning-zenoh-ros2-lp3/3-emulate-a-wireless-link.md @@ -0,0 +1,290 @@ +--- +title: Tune Zenoh on an emulated wireless link +weight: 4 + +layout: learningpathall +--- + +## Apply network constraints (A1) + +Linux traffic control (`tc`) decides how packets leave a network interface. Its network emulator (`netem`) can add delay, loss, duplication, corruption, and reordering. Together they let you reproduce a difficult network without moving the containers to Wi-Fi. + +In a `robot` terminal: + +```bash +just network_limit +``` + +**Expected result:** the script reports the emulated link parameters. + +```output +WiFi medium connection simulation applied to 172.1.0.3: + - Rate: 25mbit + - Latency: 20ms ± 10ms + - Packet loss: 0.5% + - Reordering: 1% 25% + - Duplicates: 0.1% + - Corruptions: 0.01% +``` + +The 25 Mbps rate is a maximum, not a guaranteed result. TCP can send less than the limit when it reacts to loss and reordering. + +Restart the measurements and record: + +| Scenario | `/scan` | `/camera/image_raw` | `/camera/points` | Link traffic | +|---|---|---|---|---| +| **A1: Constrained** | **7.94 Hz — unaffected** | **0.88 Hz** (std 0.577 s, max gap 6.3 s) | **nothing received** | **~23.5 Mbps (at the cap)** | + +Three messages, three outcomes. The scan is untouched: it is small, and it has a connection of its own. +`/camera/image_raw` slows down, becomes irregular, or receives no complete frames during the window. The point cloud disappears entirely. + +Stop all four measurement commands with **Ctrl+C**. + +## Apply compression (A2) + +Zenoh uses [LZ4 compression](https://lz4.org/) to reduce the bytes sent over a unicast connection. LZ4 was chosen for speed rather than ratio, since compression must not become a latency source. Compression is negotiated when a client connects, so the router and the client must both enable it. + +In a `robot` terminal, open the router configuration: + +```bash +nano ~/container_data/ROUTER_CONFIG.json5 +``` + +Find the existing `transport/unicast/compression` section and set `enabled` to `true`: + +```json5 +compression: { + enabled: true, +}, +``` + +Do not add a second `transport` block. Edit the active value rather than a commented example. + +In a `control` terminal, open the client configuration: + +```bash +nano ~/container_data/SESSION_CONFIG.json5 +``` + +Find the same compression setting and set it to `true`. + +Save each file with **Ctrl+O** and **Enter**, then exit Nano with **Ctrl+X**. + +The router reads its configuration only at startup. In the `robot` desktop, find the terminal running the router, press Ctrl+C, then restart it: + +```bash +just router +``` + +Restart the four measurements and record: + +| Scenario | `/scan` | `/camera/image_raw` | `/camera/points` | Link traffic | +|---|---|---|---|---| +| **A2** | **7.95 Hz** (link traffic ~380 Kbps → ~200 Kbps) | **0.5–2.8 Hz, drifting** | **still nothing** | **~23.5 Mbps, still at the cap** | + +The scan's rate is unchanged but its bytes on the link roughly halve — LZ4 achieving about 1.8× on this data. The image improves, but the reading drifts between measurements, while the point cloud's doomed fragments still compete for the link. An unstable reading here is the expected result, not a mistake. + +The total TX rate (Link traffic) can remain close to the constrained link’s capacity. Compression reduces individual messages, but publishers continue supplying more data than the link can carry. + +Stop all four measurement commands with **Ctrl+C**. Keep compression enabled and keep the network limit active for the next scenario. + +## Add an access-control rule (A3) + +A monitoring station does not always need the point cloud. Zenoh access control can stop that topic at the router while local robot nodes continue to use it. + +Open the router configuration in `robot`: + +```bash +nano ~/container_data/ROUTER_CONFIG.json5 +``` + +Add this `access_control` block at the top level of the file. Do not place it inside `transport`: + +```json5 +access_control: { + enabled: true, + default_permission: "allow", + rules: [ + { + id: "deny_points_cloud", + permission: "deny", + messages: [ + "put", "delete", "declare_subscriber", + "query", "reply", "declare_queryable", + "liveliness_token", "liveliness_query", "declare_liveliness_subscriber", + ], + flows: ["egress", "ingress"], + key_exprs: [ + "*/camera/points/**", + "*/camera/points/**/@adv/**", + ], + }, + ], + subjects: [ + { id: "ALL" }, + ], + policies: [ + { + id: "deny_points_cloud_to_all", + rules: ["deny_points_cloud"], + subjects: ["ALL"], + }, + ], +}, +``` + +The first key expression matches the point-cloud data. The `@adv` form matches the additional keys used to advertise topics with transient-local durability. + +Save the file, stop the router with **Ctrl+C**, and restart it: + +```bash +just router +``` + +Restart the three measurements in `control` and `just iftop_router` in `robot`. Wait 60–90 seconds and complete the A3 row: + +| Scenario | `/scan` | `/camera/image_raw` | `/camera/points` | Link traffic | +|---|---|---|---|---| +| **A3** | **7.97 Hz** | **0.84 Hz** (still bursty, max gap 11.4 s) | **blocked — and the connection drops to zero** | **~9.4 Mbps — the link is no longer saturated** | + +Verify the asymmetry from both sides — this is the point of the exercise: + +```bash +# control container: nothing arrives +ros2 topic bw /camera/points + +# robot container: unchanged +ros2 topic hz /camera/points +``` + +**Expected result:** the control container receives nothing while the robot's own nodes still exchange the point cloud at about 12 Hz. The rule governs what crosses the router, not what happens inside the robot. + +Note that `/camera/points` still appears in the remote `ros2 topic list` even though no data arrives — the block stops the data, not the graph entry. + +Stop all measurement commands with **Ctrl+C**. Keep compression, access control, and the network limit active. + +## Downsample the image (A4) + +Downsampling drops publications on the egress path to a target frequency. + +Keep the A3 access-control block active. Open the router configuration in `robot`: + +```bash +nano ~/container_data/ROUTER_CONFIG.json5 +``` + +Add this block at the top level: + +```json5 +downsampling: [ + { + messages: ["put", "reply"], + flows: ["egress"], + rules: [ + { key_expr: "*/camera/image_raw/**", freq: 3.0 }, + { key_expr: "*/camera/image_raw/**/@adv/**", freq: 3.0 }, + ], + }, +], +``` +The rule sets a maximum egress rate of 3 Hz for the image and its transient-local advertisement keys. + +Save the file, stop the router, and restart it: +```bash +just router +``` + +Restart the measurements and record: + +| Scenario | `/scan` | `/camera/image_raw` | `/camera/points` | Link traffic | +|---|---|---|---|---| +| **A4** | **8.0 Hz** | **2.6 Hz, std dev 0.06 s** — steady | **blocked** | **~6.8 Mbps** | + +The remote camera rate should settle near, but not necessarily exactly at, 3 Hz. Compare its standard deviation with A3. A lower standard deviation means the frames arrive more regularly instead of in bursts. + +This is the important result: a steady rate below the connection’s usable capacity gives the transmit queue time to drain between frames. A stable 2.6 Hz stream can be more useful to an operator than a lower average made from short bursts and long pauses. + +Stop all measurement commands with **Ctrl+C**. + +## Apply priority and congestion control (A5) + +The remaining problem is the point cloud, which so far has only ever been blocked, never delivered. This step restores point-cloud traffic and changes the congestion policy. + +Open `~/container_data/ROUTER_CONFIG.json5` in robot. Comment out the `access_control` and `downsampling` blocks — keep them in the file, Experiment B needs them again. Add this `qos` block at the top level: + +```json5 +qos: { + network: [ + { + interfaces: ["eth0"], + key_exprs: ["**/map/**", "**/scan/**"], + messages: ["put", "query"], + overwrite: { priority: "interactive_high" } + }, + { + interfaces: ["eth0"], + key_exprs: ["**/robot_description/**"], + messages: ["put", "query"], + overwrite: { priority: "interactive_low" } + }, + { + interfaces: ["eth0"], + key_exprs: ["**/camera/image_raw/**"], + messages: ["put"], + overwrite: { priority: "data_low" } + }, + { + interfaces: ["eth0"], + key_exprs: ["**/camera/points/**"], + messages: ["put"], + overwrite: { priority: "background" } + }, + { + interfaces: ["eth0"], + payload_size: "4096..", + messages: ["put"], + overwrite: { congestion_control: "block_first" } + }, + ], +}, +``` + +Verify the state of all three blocks before restarting: +```bash +grep -n "access_control\|downsampling\|qos\|block_first" ~/container_data/ROUTER_CONFIG.json5 +``` + +Restart the router and the measurements. + +| Scenario | `/scan` | `/camera/image_raw` | `/camera/points` | Link traffic | +|---|---|---|---|---| +| **A5** | **7.9 Hz** | **4.4 Hz, std dev 0.08 s** | **delivered: 2.0–3.0 MB/s — a complete 7.37 MB frame every ~3 s** | **~17.2 Mbps, all of it useful** | + +For the first time under the constrained link, `ros2 topic bw /camera/points` should report complete 7.37 MB messages. The average bandwidth will be much lower than A0 because a complete frame can take several seconds to arrive. + +When the queue is full, `block_first` waits for the first matching message to progress and can drop later matching messages. This favors complete point-cloud frames over fragments from several competing frames, so fewer frames arrive, but the received frames are usable. + +Stop the measurements with **Ctrl+C**. Restore the normal Docker network in `robot`: + +```bash +just network_normal +``` + +## Compare the Experiment A results + +The complete comparison shows how each policy changes the traffic delivered over the same constrained link: + +| Scenario | `/scan` | `/camera/image_raw` | `/camera/points` | Link traffic | +|---|---|---|---|---| +| A0: Baseline | 7.97 Hz | 11.85 Hz | ~88 MB/s | ~810 Mbps | +| A1: Constrained | 7.94 Hz | 0.88 Hz | Nothing received | ~23.5 Mbps | +| A2: Compression | 7.95 Hz | 0.5–2.8 Hz, drifting | Nothing received | ~23.5 Mbps | +| A3: Compression and access control | 7.97 Hz | 0.84 Hz, bursty | Blocked | ~9.4 Mbps | +| A4: Compression, access control, and downsampling | 8.0 Hz | 2.6 Hz, steady | Blocked | ~6.8 Mbps | +| A5: Compression and QoS | 7.9 Hz | 4.4 Hz, steady | 2.0–3.0 MB/s | ~17.2 Mbps | + +## What you've accomplished and what's next + +You've reproduced a constrained wireless link and measured how each Zenoh policy changes the result. Compression reduced the bytes sent but could not deliver the point cloud by itself. Access control removed unwanted traffic, downsampling made the camera stream steadier, and `block_first` allowed complete point-cloud frames to arrive. + +You have also restored the normal Docker network. Next, you'll repeat the comparison with a Raspberry Pi over real Wi-Fi. diff --git a/content/learning-paths/cross-platform/tuning-zenoh-ros2-lp3/4-measure-real-wifi.md b/content/learning-paths/cross-platform/tuning-zenoh-ros2-lp3/4-measure-real-wifi.md new file mode 100644 index 0000000000..69976e50b7 --- /dev/null +++ b/content/learning-paths/cross-platform/tuning-zenoh-ros2-lp3/4-measure-real-wifi.md @@ -0,0 +1,168 @@ +--- +title: Measure with real Wi-Fi +weight: 5 + +layout: learningpathall +--- + +## Experiment B: real Wi-Fi + +Experiment B changes one part of the topology: + +```text +Experiment A: robot container ── Docker network ── control container +Experiment B: robot container ── Arm server ── Wi-Fi ── Raspberry Pi +``` + +Put the Raspberry Pi on Wi-Fi (2.4 GHz makes the effects clearer). Connect it as a Zenoh client, just as was done in the [previous Learning Path](/learning-paths/cross-platform/distributed-ros2-zenoh-lp2/3-connect-the-raspberry-pi/). + +## Restore the B0 router configuration + +Before starting, return the router configuration to a clean state. Open `~/container_data/ROUTER_CONFIG.json5` in `robot` and ensure the following: + +- Set `transport/unicast/compression/enabled` to `false` +- Keep `access_control`, `downsampling`, and `qos` commented out + +Restart the router after saving the file. Confirm that the emulated link is no longer active: + +```bash +just network_normal +``` + +Experiment B uses the physical wireless link. Do not run `just network_limit` during these scenarios. + +## Record scenario B0 + +Open three SSH sessions to the Raspberry Pi. In each session, enter `pi_edge` and source ROS 2: + +```bash +docker exec -it pi_edge bash +source /opt/ros/jazzy/setup.bash +``` + +Run one receiver command in each container shell: + +```bash +ros2 topic hz /scan +``` + +```bash +ros2 topic hz /camera/image_raw +``` + +```bash +ros2 topic bw /camera/points +``` + +Run `just iftop_router` in `robot`. Wait 60–90 seconds and complete the B0 row: + +| Scenario | `/scan` | `/camera/image_raw` | `/camera/points` | Link traffic | +|---|---|---|---|---| +| **B0** untuned | 7.90 Hz | 4.2 Hz | nothing (wasting ~28 Mbps) | ~62 Mbps, nearly half of it wasted | + +A common B0 pattern is an intact laser scan, a reduced or irregular camera rate, and no complete point-cloud frames. `iftop` can show substantial point-cloud traffic even while `ros2 topic bw` remains silent. Those bytes belong to incomplete frames. + +Real Wi-Fi results vary with signal strength, distance, interference, access-point load, and other devices using the same channel. Record what you observe rather than treating the reference values as targets. + +Stop the three measurements and `iftop` with **Ctrl+C**. + +## Enable compression (B1) + +Keep the three Pi shells open after stopping the B0 measurements. In `robot`, enable compression in `~/container_data/ROUTER_CONFIG.json5`. Keep `access_control`, `downsampling`, and `qos` commented out. + +Enable compression in each Pi shell: + +```bash +export ZENOH_CONFIG_OVERRIDE="${ZENOH_CONFIG_OVERRIDE};transport/unicast/compression/enabled=true" +``` + +Confirm that the override includes compression: + +```bash +echo $ZENOH_CONFIG_OVERRIDE +``` + +Stop and restart the router so that it reads the new configuration. Restart the same three Pi measurements used for B0, run `just iftop_router` in `robot`, and collect data for 60–90 seconds. + +Record your measurements and compare them with the reference result: + +| Scenario | `/scan` | `/camera/image_raw` | `/camera/points` | Link traffic | +|---|---|---|---|---| +| **B1: Compression** | **7.85 Hz** | **11.87 Hz — source rate** | **Nothing received** (~26 Mbps wasted) | **~55.7 Mbps** | + +Compression allows the camera images to fit the real Wi-Fi link, restoring the source frame rate. The point cloud still fails because the default congestion policy discards fragments before a complete frame arrives. + +## Downsample the camera (B2) + +Stop the B1 measurements and `iftop`. In the router configuration, disable compression and enable only the `downsampling` block from A4. Keep `access_control` and `qos` commented out. + +The current Pi shells still contain the compression override from B1. Exit each container shell, open a fresh one, and source ROS 2: + +```bash +exit +docker exec -it pi_edge bash +source /opt/ros/jazzy/setup.bash +``` + +Do not enable compression in these new shells. Stop and restart the router, restart the three Pi measurements, run `just iftop_router` in `robot`, and collect data for 60–90 seconds. + +Record your measurements and compare them with the reference result: + +| Scenario | `/scan` | `/camera/image_raw` | `/camera/points` | Link traffic | +|---|---|---|---|---| +| **B2: Downsampling** | **7.94 Hz** | **2.37 Hz — steady** | **Nothing received** despite using 58–61 Mbps | **~64 Mbps** | + +The camera settles near the 3 Hz target with less jitter. The point-cloud connection uses the bandwidth released by the camera and still delivers no complete frames. More available bandwidth has not solved the large-message problem. + +## Compress and block the point cloud (B3) + +Stop the B2 measurements and `iftop`. In the router configuration, disable downsampling, enable compression, and enable the `access_control` block from A3. Keep `qos` commented out. + +Enable compression in each Pi shell: + +```bash +export ZENOH_CONFIG_OVERRIDE="${ZENOH_CONFIG_OVERRIDE};transport/unicast/compression/enabled=true" +``` + +Stop and restart the router, restart the three Pi measurements, run `just iftop_router` in `robot`, and collect data for 60–90 seconds. + +Record your measurements and compare them with the reference result: + +| Scenario | `/scan` | `/camera/image_raw` | `/camera/points` | Link traffic | +|---|---|---|---|---| +| **B3: Compression and access control** | **7.85 Hz** | **11.89 Hz** | **Blocked** | **~29 Mbps, all useful** | + +The point cloud now consumes no link bandwidth, while the camera and scan remain available. This configuration suits remote monitoring when the operator does not need three-dimensional data. + +## Compress and deliver complete large messages (B4) + +Stop the B3 measurements and `iftop`. In the router configuration, comment out the access-control block, keep compression enabled, and enable the `qos` block from A5. Keep downsampling disabled. + +The Pi shells already have compression enabled, so no client-side change is needed. Stop and restart the router, restart the three Pi measurements, run `just iftop_router` in `robot`, and collect data for 60–90 seconds. + +Record your measurements and compare them with the reference result: + +| Scenario | `/scan` | `/camera/image_raw` | `/camera/points` | Link traffic | +|---|---|---|---|---| +| **B4: Compression and QoS** | **7.89 Hz** | **11.88 Hz, std dev 0.019 s** | **~1 complete frame/s** | **~63 Mbps, all useful** | + +The point-cloud terminal now reports complete 7.37 MB frames at the rate supported by the Wi-Fi connection. The camera and scan continue alongside it. + +## Compare the Experiment B results + +The complete comparison shows that similar link rates can carry very different amounts of useful ROS 2 data: + +| Scenario | `/scan` | `/camera/image_raw` | `/camera/points` | Link traffic | +|---|---|---|---|---| +| B0: Untuned | 7.90 Hz | 4.2 Hz | Nothing received | ~62 Mbps, nearly half wasted | +| B1: Compression | 7.85 Hz | 11.87 Hz | Nothing received | ~55.7 Mbps | +| B2: Downsampling | 7.94 Hz | 2.37 Hz, steady | Nothing received | ~64 Mbps | +| B3: Compression and access control | 7.85 Hz | 11.89 Hz | Blocked | ~29 Mbps, all useful | +| B4: Compression and QoS | 7.89 Hz | 11.88 Hz, steady | ~1 complete frame/s | ~63 Mbps, all useful | + + +## What you've accomplished and what's next + +You've repeated the policy comparison over real Wi-Fi. Compression restored the camera rate, access control removed an unwanted flow, downsampling produced a steady lower-rate stream, and `block_first` delivered complete point-cloud frames. + +The comparison shows that tuning does not need to increase the available bandwidth. It changes how the bandwidth is used and which complete messages reach the receiver. Next, you'll select a configuration for the needs of your deployment. diff --git a/content/learning-paths/cross-platform/tuning-zenoh-ros2-lp3/5-select-a-deployment-policy.md b/content/learning-paths/cross-platform/tuning-zenoh-ros2-lp3/5-select-a-deployment-policy.md new file mode 100644 index 0000000000..a6cea827dd --- /dev/null +++ b/content/learning-paths/cross-platform/tuning-zenoh-ros2-lp3/5-select-a-deployment-policy.md @@ -0,0 +1,45 @@ +--- +title: Select a deployment policy +weight: 6 + +layout: learningpathall +--- + +## Select a configuration for your deployment + +The experiments show that the right configuration depends on which sensor data the remote application needs. + +### Remote monitoring only: compression and access control + +Use compression and access control when the remote station needs camera images and laser scans, but not the point cloud. + +Enable `transport/unicast/compression` at both ends of the link. On the router, deny `*/camera/points/**` and its `*/camera/points/**/@adv/**` variant. + +The camera runs at its full source rate, `/scan` remains available, and the point cloud consumes no link bandwidth. For a remote station that only needs to monitor the robot, these two settings are sufficient. + +### Large messages required: compression and QoS + +Use compression and QoS when complete point-cloud frames must reach the remote device. + +Keep compression enabled and add the quality of service (QoS) `qos/network` block. Give important topics higher priority, and set `congestion_control: "block_first"` for payloads larger than 4096 bytes. + +All three sensor streams can then share the link. The point cloud arrives at the rate the network supports, but each delivered frame is complete rather than a collection of unusable fragments. + +### When compressed images still do not fit: downsampling + +Use downsampling when the compressed camera stream still exceeds the available capacity. + +Set the forwarded image rate below the sustained capacity of the link. This trades frame rate for steadier delivery and lower jitter. + +## Summary + +You have now: + +- Measured message frequency, jitter, message bandwidth, and total Zenoh link traffic at the correct observation points +- Reproduced a constrained wireless link between two Docker containers with `tc` and `netem` +- Shown why small laser scans can survive while camera and point-cloud messages fail +- Reduced traffic with compression, access control, and downsampling +- Delivered complete large messages by replacing fragment-dropping behaviour with `block_first` +- Confirmed the policy effects on a Raspberry Pi over real Wi-Fi + +The available bandwidth did not need to change. Zenoh changed which messages used it and whether those messages arrived in a form the ROS 2 receiver could use. diff --git a/content/learning-paths/cross-platform/tuning-zenoh-ros2-lp3/_index.md b/content/learning-paths/cross-platform/tuning-zenoh-ros2-lp3/_index.md new file mode 100644 index 0000000000..e00eb2a4e8 --- /dev/null +++ b/content/learning-paths/cross-platform/tuning-zenoh-ros2-lp3/_index.md @@ -0,0 +1,78 @@ +--- +title: Tune Zenoh for ROS 2 traffic over wireless networks + +draft: true +cascade: + draft: true + +minutes_to_complete: 120 + +description: Measure ROS 2 sensor traffic, reproduce a constrained wireless link, and tune Zenoh with compression, access control, downsampling, and QoS. + +who_is_this_for: This Learning Path is for robotics developers who want to understand how Zenoh manages ROS 2 sensor traffic over Wi-Fi. You should already have basic experience setting up and distributing a ROS 2 Jazzy system with rmw_zenoh, as covered in the previous Learning Paths in this series. + +learning_objectives: + - Measure the rate, bandwidth, and regularity of ROS 2 sensor data at a remote receiver + - Reproduce a constrained wireless link with Linux traffic control + - Configure Zenoh compression, access control, downsampling, and quality of service policies + - Validate the policies over real Wi-Fi and select a suitable deployment configuration + +prerequisites: + - The ROS 2 simulation environment from Learning Path 1, with the `robot` and `control` containers available + - The distributed Zenoh configuration from Learning Path 2, with the `control` container connected in client mode + - An **Arm server** with the Docker Compose configuration used in Learning Paths 1 and 2 + - A **Raspberry Pi** connected over Wi-Fi + - Familiarity with ROS 2 topics, Docker, and basic Linux commands + +author: + - Kwashie Andoh + - Odin Shen + - Habib Ogunbanwo + +generate_summary_faq: false +rerun_summary: false +rerun_faqs: false + +skilllevels: Introductory +subjects: Performance and Architecture +armips: + - Cortex-A + - Neoverse +tools_software_languages: + - ROS 2 + - rmw_zenoh + - Zenoh + - Docker + - Linux traffic control +operatingsystems: + - Linux + +### Cross-platform metadata only +shared_path: true +shared_between: + - automotive + +further_reading: + - resource: + title: Build a ROS 2 and Zenoh simulation environment on an Arm server + link: /learning-paths/cross-platform/ros2-zenoh-arm/ + type: documentation + - resource: + title: Distribute a ROS 2 robotic system across Arm devices with Zenoh + link: /learning-paths/cross-platform/distributed-ros2-zenoh-lp2/ + type: documentation + - resource: + title: ROS 2 middleware implementation for Eclipse Zenoh + link: https://github.com/ros2/rmw_zenoh + type: documentation + - resource: + title: Eclipse Zenoh documentation + link: https://zenoh.io/docs/ + type: documentation + +### FIXED, DO NOT MODIFY +# ================================================================================ +weight: 1 # _index.md always has weight of 1 to order correctly +layout: "learningpathall" # All files under learning paths have this same wrapper +learning_path_main_page: "yes" # This should be surfaced when looking for related content. Only set for _index.md of learning path content. +--- diff --git a/content/learning-paths/cross-platform/tuning-zenoh-ros2-lp3/_next-steps.md b/content/learning-paths/cross-platform/tuning-zenoh-ros2-lp3/_next-steps.md new file mode 100644 index 0000000000..c3db0de5a2 --- /dev/null +++ b/content/learning-paths/cross-platform/tuning-zenoh-ros2-lp3/_next-steps.md @@ -0,0 +1,8 @@ +--- +# ================================================================================ +# FIXED, DO NOT MODIFY THIS FILE +# ================================================================================ +weight: 21 # Set to always be larger than the content in this path to be at the end of the navigation. +title: "Next Steps" # Always the same, html page title. +layout: "learningpathall" # All files under learning paths have this same wrapper for Hugo processing. +--- diff --git a/content/learning-paths/cross-platform/tuning-zenoh-ros2-lp3/a0-iftop-baseline.png b/content/learning-paths/cross-platform/tuning-zenoh-ros2-lp3/a0-iftop-baseline.png new file mode 100644 index 0000000000..54f2b601ad Binary files /dev/null and b/content/learning-paths/cross-platform/tuning-zenoh-ros2-lp3/a0-iftop-baseline.png differ