Skip to content

Buffers

Infrastructure Banner

ROS 2 Jazzy

Jetson Xavier NX

ubuntu 24.04


Network Buffers wmem rmem#

DDS sends and receives data through OS-managed socket buffers known as rmem (Receive Memory Buffer) and wmem (Write Memory Buffer)

MICIPSA Banner

Two kernel parameters control their maximum size:

Parameter Controls Default Recommended
wmem_max Max send buffer size per socket ~200 KB 64 MB
wmem_default Default send buffer size ~200 KB 64 MB
rmem_max Max receive buffer size per socket ~200 KB 64 MB
rmem_default Default receive buffer size ~200 KB 64 MB

If wmem is too small publisher drops frames before they even leave the machine. For example Camera images and LiDAR scans appear briefly then disappear.

If rmem is too small then incoming packets are silently dropped at the OS level before ROS ever sees them.

CycloneDDS requires significantly larger UDP socket receive buffers than the Linux default (~212 KB). Without this, node initialization fails with the following error: failed to increase socket receive buffer size


Setting rmem wmem Values#

These values must be applied on every machine running ROS 2 nodes, both the robot and the base station.

Setting rmem_max / wmem_max to arbitrarily large values is a common misconfiguration. Assigning the _max parameters to 2147483647 (2GB the 32-bit integer ceiling) does not improve performance. The _max parameter defines the upper bound that any individual socket is permitted to request, while _default defines the baseline allocated to every new socket that does not explicitly request a size. A _max of 2GB does not pre-allocate that memory, but it permits any single process to request up to that amount through socket buffers, a significant risk on memory-constrained platforms, 64MB is sufficient for ROS 2 workloads combining camera and LiDAR traffic.

Both _max and _default should be set to the same value and the rmem and wmem parameters should always be configured symmetrically.

Important

You can use the network installer script to automatically configure the buffer values, or configure them manually. (recommended)

Start with Standard Method fix.

If the values still reset after reboot, it means that your platform applies sysctl too early in the boot sequence, follow Advanced Method fix instead.

To define a more accurate value that matches your needs, please read Determining the Required Buffer Size


Network Script Installer#

cd ~/ros2_ws/src/micipsa/infra/scripts/installers
chmod +x install_network.sh
sudo ./install_network.sh

Standard Method#

echo "net.core.rmem_max=67108864"     | sudo tee -a /etc/sysctl.d/99-micipsa_network.conf
echo "net.core.rmem_default=67108864" | sudo tee -a /etc/sysctl.d/99-micipsa_network.conf
echo "net.core.wmem_max=67108864" | sudo tee -a /etc/sysctl.d/99-micipsa_network.conf
echo "net.core.wmem_default=67108864" | sudo tee -a /etc/sysctl.d/99-micipsa_network.conf
sudo sysctl -p

Note

The 99- prefix ensures this config file loads after all other sysctl rules.

After rebooting, verify the values persisted:

sysctl net.core.rmem_max net.core.rmem_default net.core.wmem_max net.core.wmem_default

Advanced Method#

On some platforms (notably NVIDIA Jetson running L4T), the standard sysctl.conf / sysctl.d approach does not survive a reboot, even though sudo sysctl -p applies it correctly at runtime.

Jetson's L4T uses a boot system with a init.d script called procps, symlinked as S01procps, meaning it runs as the very first process at boot (runlevel S, single-user mode, before the network stack exists):

/etc/rcS.d/S01procps -> ../init.d/procps

This script correctly applies sysctl values via sysctl --system, but the network stack hasn't initialized yet at that point. When it comes up shortly after (via nvethernet, l4tbr0, NetworkManager, etc.), the kernel resets socket buffer defaults back to 212992.

On standard Ubuntu, systemd-sysctl runs late enough to avoid this. On Jetson, init.d/procps runs far too early.

Problem Diagnosis#

On a fresh reboot:

1. Check Runtime Values#
sysctl net.core.rmem_max net.core.rmem_default net.core.wmem_max net.core.wmem_default
2. Confirm Sysctl Applies Correctly Manually#
sudo sysctl --system
sysctl net.core.rmem_max net.core.rmem_default net.core.wmem_max net.core.wmem_default
3. Confirm Early Boot Ordering Of procps#
ls -la /etc/rcS.d/ | grep procps
# Expected: S01procps -> ../init.d/procps  (runs first at boot)
4. Inspect Init Script#
cat /etc/init.d/procps
# Relevant lines:
# X-Start-Before: $network   ← runs before network is up
# Default-Start:  S          ← runlevel S = very early single-user boot

Applying Fix#

Use /etc/rc.local. The rc-local.service unit is started by systemd after multi-user.target, NetworkManager, and all other services, meaning nothing runs after it to undo the kernel values.

1. Create or edit /etc/rc.local#
sudo nano /etc/rc.local

Paste the following content:

#!/bin/sh -e
/sbin/sysctl -w net.core.rmem_max=67108864
/sbin/sysctl -w net.core.rmem_default=67108864
/sbin/sysctl -w net.core.wmem_max=67108864
/sbin/sysctl -w net.core.wmem_default=67108864
exit 0
2. Make It Executable#
sudo chmod +x /etc/rc.local
3. Reboot#
sudo reboot

Note

Any entries in /etc/sysctl.conf or /etc/sysctl.d/99-micipsa_network.conf can be kept as documentation or reference, but on Jetson they are not what applies the values at runtime, /etc/rc.local is.


Checking rmem wmem Values#

sysctl net.core.rmem_max net.core.rmem_default net.core.wmem_max net.core.wmem_default

or

cat /proc/sys/net/core/wmem_max
cat /proc/sys/net/core/wmem_default
cat /proc/sys/net/core/rmem_max
cat /proc/sys/net/core/rmem_default

Expected output:

net.core.rmem_max = 67108864
net.core.rmem_default = 67108864
net.core.wmem_max = 67108864
net.core.wmem_default = 67108864

Determining the Required Buffer Size#

Note

For most ROS 2 systems running camera and LiDAR simultaneously, 64 MB is enough without needing to calculate

Buffer sizing is not arbitrary, it can be derived from your actual network conditions using the following formula:

buffer size = total_bandwidth × max_acceptable_latency × safety_factor

1. Measure actual topic bandwidth#

Run the following on the robot to measure what your topics are producing:

ros2 topic bw /front_camera/color/image_raw
ros2 topic bw /scan
ros2 topic bw /tf
.
.
.
etc

Example output:

/front_camera/color/image_raw  →  15.0 MB/s
/scan                          →   0.5 MB/s
/tf                            →   0.1 MB/s
                                 ──────────
total                          →  ~16 MB/s

2. Apply the formula#

Using the measured total with a conservative safety factor:

buffer = 16 MB/s × 0.1s × 4 = 6.4 MB

Round up to the next power of two: 8 MB minimum.

3. Add operational headroom#

The calculated minimum covers steady-state traffic only. In practice, sensor data is bursty, a LiDAR scan arrives all at once, not spread evenly across the interval. A headroom multiplier of 8–10× is standard for robotics workloads, which is how the community-standard value of 64 MB is reached.