Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Environment Variables Reference

Configuration File

All environment variables can be set in a .env file at the project root:

cp .env.example .env
# Edit .env — uncomment and adjust values as needed
  • justfile — .env is auto-loaded. Missing file silently ignored.
  • direnv — .envrc sources .env if present.
  • Manual — set -a; source .env; set +a before cargo build.

Variables in .env take precedence over justfile defaults but are overridden by explicit shell exports.

Runtime Configuration

Examples use ExecutorConfig::from_env() for configuration:

VariableDescriptionDefault
ROS_DOMAIN_IDROS 2 domain ID0
NROS_LOCATORRMW locator (tcp/…, udp/…, serial/…, or tls/…)tcp/127.0.0.1:7447
NROS_SESSION_MODESession mode: client or peerclient
ZENOH_TLS_ROOT_CA_CERTIFICATEPath to CA certificate (PEM) for TLS(none)
ZENOH_TLS_ROOT_CA_CERTIFICATE_BASE64Base64-encoded CA certificate for TLS(none)
ZENOH_TLS_VERIFY_NAME_ON_CONNECTVerify server hostname in TLS (true/false)(none)

Retired legacy names (phase-484 W8c): ZENOH_LOCATOR and ZENOH_MODE are no longer read. Setting either is a startup ERROR naming its replacement (NROS_LOCATOR / NROS_SESSION_MODE) — Rust panics in resolve_hosted / returns InitError::RetiredEnvVar from nros::init, C / C++ init returns RCL_RET_INVALID_ARGUMENT / NROS_CPP_RET_INVALID_ARGUMENT and logs the reason. Refused rather than ignored: an ignored locator would dial the default router and read as “no delivery”. ZENOH_TLS_* names are kept because TLS is currently zenoh-specific.

TLS Notes

  • POSIX: requires libmbedtls-dev (just setup base checks it). File-path and base64 cert loading are both supported.
  • Bare-metal: only ZENOH_TLS_ROOT_CA_CERTIFICATE_BASE64 is supported (no filesystem). The certificate is embedded at build time.
  • The link-tls Cargo feature must be enabled on both the example and the nros crate.

Build-Time Configuration

VariableDescriptionRequired
ZENOH_PICO_DIRCMake install prefix for pre-built zenoh-pico (use with system-zenohpico feature on zpico-sys)Only with system-zenohpico
SSIDWiFi network name for ESP32 examplesRequired for build-examples-esp32
PASSWORDWiFi password for ESP32 examplesRequired for build-examples-esp32
NROS_EXTRA_BOARD_PATHExtra board-search roots (PATH-style : separated). Each entry is a directory shaped like packages/boards/ — subdirs carrying nros-board.toml crates or */boards/<name>/board.cmake bundles. Read by the nros CLI’s board catalog AND nano_ros_use_board() (also settable as a CMake cache var there). Board keys stay global: a name found under two roots is an error, never shadowed.(unset)

ARM FVP (FVP_BaseR_AEMv8R)

Not license-gated: nros setup --tool arm-fvp fetches the model from a pinned Arm CDN permalink ([tool.arm-fvp] in nros-sdk-index.toml, digest-checked) into the SDK store. Arm publishes it for x86_64 Linux only. You need none of the variables below unless you installed a model yourself. See the ARM FVP getting-started chapter for the end-to-end build+run walk-through.

VariableDescriptionDefault
ARMFVP_BIN_PATHDirectory containing FVP_BaseR_AEMv8R (Zephyr-canonical, highest priority).(unset)
ARM_FVP_DIRInstall root; resolver scans models/Linux64_GCC-*/ underneath.(unset)

scripts/zephyr/resolve-fvp-bin.sh resolves, in order: ARMFVP_BIN_PATH, ARM_FVP_DIR, FVP_BaseR_AEMv8R on PATH, then the store copy (nros sdk-path arm-fvp). The just zephyr run-fvp-* / verify-fvp-runtime recipes export the result as ARMFVP_BIN_PATH at BUILD time as well as run time, because Zephyr’s armfvp.cmake caches the location at configure. When nothing resolves, a recipe you NAMED fails with the remedy (nros setup --tool arm-fvp); reached through a fixture fan-out it skips and is reported.

For a model you downloaded by hand, scripts/installers/arm-fvp-installer.sh (with ARM_FVP_DIR set to the extraction root) symlinks it to ~/.nros/sdks/arm-fvp/current/ and prints the export ARMFVP_BIN_PATH=… line. nros doctor --board fvp-aemv8r-smp reports whether the model resolves.

Vendored source trees

You normally set none of these. nros setup puts each tree in the shared store, and every build locates it through one ladder (RFC-0103 D3): this variable, then the project’s [sources] row in system.toml, then a checkout submodule you are editing, then the store, then the checkout’s own copy. nros locate <name> --why prints which rung answered. Set a variable only to build against a tree of your own.

VariableTree
FREERTOS_DIRFreeRTOS kernel source
LWIP_DIRlwIP source
NUTTX_DIRNuttX RTOS source
NUTTX_APPS_DIRNuttX apps source
THREADX_DIRThreadX kernel source
NETX_DIRNetX Duo source
CYCLONEDDS_SOURCE_DIRCyclone DDS source

FREERTOS_PORT, FREERTOS_CONFIG_DIR, THREADX_CONFIG_DIR and NETX_CONFIG_DIR are board facts: each board’s nros-board.toml states them, and the build carries them from there. They are not user inputs.

Buffer Tuning

All optional – platform-appropriate defaults apply if unset. See Configuration for deployment-scenario guidance and platform guides for target-specific sizing.

Zenoh-pico (NROS_ZENOH_*)

Each knob here was spelled ZPICO_<X> before phase-484 W5a (RFC-0103 D2b). That old spelling is now retired (phase-484 W8): set in the environment or in an [image.<id>] env row, it stops the build with an error naming the NROS_ZENOH_* name to use. The full list is the retired-names table.

VariableDescriptionDefaultCrate
NROS_ZENOH_FRAG_MAX_SIZEMax reassembled message size after defragmentation65536 / 2048zpico-sys
NROS_ZENOH_BATCH_UNICAST_SIZEMax unicast batch size before fragmentation65536 / 1024zpico-sys
NROS_ZENOH_BATCH_MULTICAST_SIZEMax multicast batch size8192 / 1024zpico-sys
NROS_ZENOH_MAX_PUBLISHERSMax concurrent publishers in zenoh shim8zpico-sys
NROS_ZENOH_MAX_SUBSCRIBERSMax concurrent subscribers in zenoh shim8zpico-sys
NROS_ZENOH_MAX_QUERYABLESMax concurrent queryables in zenoh shim8zpico-sys
NROS_ZENOH_MAX_LIVELINESSMax concurrent liveliness tokens in zenoh shim. DERIVED when the image declares anything: one per node name plus the session’s own, one per publisher, subscriber, service server and client, and the parameter and lifecycle families’ servers and publisher (issue 1713). A stated value wins.16 when nothing is declaredzpico-sys
NROS_ZENOH_MAX_PENDING_GETSMax concurrent in-flight service calls4zpico-sys
NROS_ZENOH_MAX_TL_PUBLISHERSRetention slots for TRANSIENT_LOCAL publishers in the zenoh shim. Each also takes one NROS_ZENOH_MAX_QUERYABLES slot: a transient-local publisher declares a queryable so a late joiner can query its last sample. An image whose endpoints are declared DERIVES this (an action_server row counts one for its /status), and a stated value below the declared demand fails the build naming the knob.2nros-rmw-zenoh
NROS_ZENOH_TL_RETAIN_BYTESBytes one retained TRANSIENT_LOCAL sample may hold. A larger publish is SENT but not retained, and says so once at WARN.1024nros-rmw-zenoh
NROS_ZENOH_TL_RETAIN_DEPTHSamples each TRANSIENT_LOCAL publisher retains and replays, oldest first, to a late joiner. DERIVED from the deepest KEEP_LAST(N) a transient-local publisher declares (issue 1709); the publisher is granted and advertises min(asked, this). Must be >= 1.1 when nothing is declarednros-rmw-zenoh
NROS_SUBSCRIBER_BUFFER_SIZEsmall receive-class slot per subscriber in the zenoh shim; the executor arena reads the same name. (ZPICO_SUBSCRIBER_BUFFER_SIZE is a dead spelling — nothing reads it, issue 1181.)1024nros-rmw-zenoh
NROS_ZENOH_SUBSCRIBER_LARGE_SIZElarge size-class slot, for subscriptions whose type does not fit the small block16384nros-rmw-zenoh
NROS_ZENOH_SUBSCRIBER_SIZE_THRESHOLDThe small/large class split: a subscription whose rx_buffer_hint exceeds it is served from large. The cmake message-bound derivation assumes the shipped value (NROS_MESSAGE_BOUNDS_DEFAULT_SMALL_CEILING), so moving it can make a derived class count disagree with runtime routing, which surfaces as a failed create_subscription.2048nros-rmw-zenoh
NROS_ZENOH_PUBLISHER_TX_BUFFER_SIZEPer-publisher TX arena for the zero-copy loan path; costs NROS_ZENOH_MAX_PUBLISHERS x this (issue 0813).1024nros-rmw-zenoh
NROS_ZENOH_MAX_LARGE_SUBSCRIBERSHow many large-class blocks this image reserves. 0 is legal (phase-403 W4): an image whose subscribed types all fit NROS_SUBSCRIBER_BUFFER_SIZE declares 0 and stops paying RING_DEPTH x LARGE_SIZE — 65,536 B at the defaults — for a class it never routes into. A hint no class can hold then fails create_subscription rather than dropping every sample. DERIVED, on both lanes — a Zephyr image gets it from Kconfig’s -1 sentinel, and since issue 1125 a cargo leaf gets it from nros sync’s gitignored .cargo/nros-managed-env.toml, joined over the types the leaf’s own components subscribe to. Setting it here still wins.2nros-rmw-zenoh
NROS_ZENOH_SERVICE_BUFFER_SIZEPer-service-server static buffer in zenoh shim1024nros-rmw-zenoh
NROS_PARAM_SERVICE_INBOX_BYTESBytes one request slot holds in the inbox ring of a ROS parameter service queryable (six per node) or a REP-2002 lifecycle one (five per node) – the BUILTIN family, which the zenoh shim selects by service name (phase-461 W2b). DERIVED: with nothing stated, the contract’s declared parameters bound it, as the largest request a set_parameters over the worst-declared node can produce (672 B on the Autoware Safety Island, against the transport’s 1,024). A contract declaring a string- or array-valued parameter needs the parameter store’s capacities to price, which the RMW cannot see, so the shim abstains there and the user-service slot stands. Setting it here still wins.derived, else NROS_SERVICE_INBOX_BYTESnros-rmw-zenoh
NROS_PARAM_SERVICE_INBOX_DEPTHRequests one parameter or lifecycle service queryable holds before the newest is dropped. One, because this traffic is one request and one reply from a client that waits (ros2 param, rclcpp’s SyncParametersClient) and a node’s services are polled serially in one spin. Raise it to 2 for an image serving a parameter dashboard. Must be >= 1.1nros-rmw-zenoh
NROS_ZENOH_GET_REPLY_BUF_SIZEStack buffer for service client replies4096zpico-sys
NROS_ZENOH_GET_POLL_INTERVAL_MSSingle-threaded polling interval in zenoh_shim_get()10zpico-sys
NROS_SMOLTCP_MAX_SOCKETSMax concurrent TCP sockets (smoltcp); brokered default since Phase 204.2. (ZPICO_SMOLTCP_MAX_SOCKETS is retired.)1 (brokered)nros-smoltcp
NROS_SMOLTCP_MAX_UDP_SOCKETSMax concurrent UDP sockets (smoltcp); 1 by default, 4 with the nros-smoltcp/rtps feature (Phase 204.2). (ZPICO_SMOLTCP_MAX_UDP_SOCKETS is retired.)1 (brokered)nros-smoltcp
NROS_SMOLTCP_BUFFER_SIZEPer-socket staging buffer (smoltcp). (ZPICO_SMOLTCP_BUFFER_SIZE is retired.)2048nros-smoltcp
NROS_SMOLTCP_CONNECT_TIMEOUT_MSTCP connection timeout (smoltcp). (ZPICO_SMOLTCP_CONNECT_TIMEOUT_MS is retired.)30000nros-smoltcp
NROS_SMOLTCP_SOCKET_TIMEOUT_MSTCP read/write timeout (smoltcp). (ZPICO_SMOLTCP_SOCKET_TIMEOUT_MS is retired.)10000nros-smoltcp

XRCE-DDS (NROS_XRCE_*)

These are read by nros-rmw-xrce-cffi’s build script, either from the environment or — on Zephyr — from CONFIG_<name> in .config. They set C #defines of the same name without the NROS_ prefix; the define is not itself an environment variable, so exporting XRCE_BUFFER_SIZE has no effect and reports no error.

VariableDescriptionDefaultMinCrate
NROS_XRCE_BUFFER_SIZEPer-slot receive buffer. See the note below — this is the receive ceiling.102464nros-rmw-xrce
NROS_XRCE_SUBSCRIBER_RING_DEPTHQueued samples per subscriber321nros-rmw-xrce
NROS_XRCE_MAX_SUBSCRIBERSMax concurrent subscribers. On Zephyr, DERIVED — see below.80nros-rmw-xrce
NROS_XRCE_MAX_SERVICE_SERVERSMax concurrent service servers. On Zephyr, DERIVED — see below.40nros-rmw-xrce
NROS_XRCE_MAX_SERVICE_CLIENTSMax concurrent service clients40nros-rmw-xrce
NROS_XRCE_STREAM_HISTORYReliable stream history depth; sizes the per-session output buffer164nros-rmw-xrce
NROS_XRCE_CUSTOM_TRANSPORT_MTUCustom transport MTU; stream buffers are MTU x STREAM_HISTORY4096128nros-rmw-xrce
NROS_XRCE_TRANSPORT_MTUUDP/TCP transport MTU, and the Zephyr default of CUSTOM_TRANSPORT_MTU4096 (Zephyr 512)128nros-rmw-xrce
NROS_XRCE_SUBSCRIBER_BUFFER_SIZESubscriber ring entry size; derived from the declared subscriptions when unstated (Zephyr: -1)BUFFER_SIZE1nros-rmw-xrce
NROS_XRCE_SERVICE_REQUEST_BUFFER_SIZEService-server request entry sizeBUFFER_SIZE1nros-rmw-xrce
NROS_XRCE_SERVICE_REPLY_BUFFER_SIZEService-client reply slot sizeBUFFER_SIZE1nros-rmw-xrce

Dropping MAX_SUBSCRIBERS, MAX_SERVICE_* and SUBSCRIBER_RING_DEPTH to 1, BUFFER_SIZE to 256, STREAM_HISTORY to 4 and CUSTOM_TRANSPORT_MTU to 512 takes the session struct from ~390 KB to ~10-20 KB.

Every variable in this table is a knob-registry row, so a project states it per image as [image.<id>.knobs.xrce] buffer_size = 256 — the name without NROS_XRCE_, lowercased (max_subscribers, max_service_servers, max_service_clients, subscriber_ring_depth, subscriber_buffer_size, service_request_buffer_size, service_reply_buffer_size, stream_history, transport_mtu, custom_transport_mtu) — rather than as an env row (RFC-0103 D6).

On Zephyr the three entity caps DERIVE, and the minimum is 0

CONFIG_NROS_XRCE_MAX_SUBSCRIBERS and CONFIG_NROS_XRCE_MAX_SERVICE_SERVERS default to -1, which means take the number from the entities this image declares (the contract sidecar beside the bringup’s launch file, or a standalone leaf’s system.toml [[component]] entities rows). A listener that declares one subscription and no service is built with one subscriber slot and zero service-server slots, which is what took the session struct from 427,968 bytes to 59,088 on the zephyr cpp listener (issue 1033). Stating a number in Kconfig or the environment still wins over the derivation, in both directions.

Zero is a legal, honoured value for all three caps — it is not rounded up to 1. So creating an entity the image never declared does not truncate silently: the create fails with InvalidConfig and the backend logs which cap it hit, which knob moves it, and that the count came from the declaration.

NROS_XRCE_SUBSCRIBER_RING_DEPTH is deliberately NOT derivable — no inventory knows how deep a burst a subscriber must survive — but it does now have a Kconfig symbol. It did not before issue 1033, which made it unsettable on Zephyr however it was spelled: a Zephyr cargo build sees only the knobs nros_cargo_build.cmake forwards, and shell exports do not survive that.

NROS_XRCE_BUFFER_SIZE is the XRCE receive ceiling

A subscriber’s receive ring entry is a fixed uint8_t data[XRCE_BUFFER_SIZE], so a subscription’s own buffer size cannot raise it: asking for create_subscription_sized::<M, 16384> still stops at 1024, because the 16384 buffer is the destination of a copy that never happens. A sample that does not fit is refused on take with MessageTooLarge.

The static cost is XRCE_SUBSCRIBER_RING_DEPTH x XRCE_BUFFER_SIZE per subscriber, which is why the default is small — raise it deliberately, and consider lowering the ring depth at the same time.

Raising it stops helping at the transport MTU: at 4096 samples arrive corrupted rather than refused, with no error and no counter. That is issue 0819, open at time of writing. Keep payloads comfortably below the MTU.

Compile-time only (not environment variables)

These are #defines in packages/rmw/xrce/nros-rmw-xrce/src/internal.h with no env or Kconfig knob. Changing them means editing that header.

DefineDescriptionDefault
XRCE_ENTITY_CREATION_TIMEOUT_MSTimeout for entity creation1000
XRCE_SERVICE_REPLY_TIMEOUT_MSPer-attempt service reply timeout50
XRCE_SERVICE_REPLY_TOTAL_MSTotal service reply budget5000
XRCE_SESSION_FLUSH_TIMEOUT_MSSession flush timeout100
XRCE_SESSION_CREATION_RETRIESSession creation retries3
XRCE_MAX_PENDING_REPLIESIn-flight service replies4
XRCE_SERVICE_REQUEST_RING_DEPTHQueued service requests per server4
XRCE_DEFAULT_AGENT_PORTDefault agent port2018

Core (NROS_*)

VariableDescriptionDefaultCrate
NROS_EXECUTOR_MAX_CBSMax executor callback slots (compile-time fixed array size)4nros-node
NROS_EXECUTOR_ARENA_SIZEExecutor arena size in bytes (compile-time fixed array size)4096nros-node
NROS_SUBSCRIPTION_BUFFER_SIZEDefault subscription/service buffer size (bytes)1024nros-node
NROS_LET_BUFFER_SIZEBuffer size for LET semantics per handle512nros-c
NROS_MAX_CONCURRENT_GOALSMax concurrent goals per action server (compile-time constant, not env-var configurable)4nros-c
NROS_MAX_PARAMETERSMax parameters in parameter server32nros-params
NROS_MAX_PARAM_NAME_LENMax parameter name length64nros-params
NROS_MAX_STRING_VALUE_LENMax string parameter value length256nros-params
NROS_MAX_ARRAY_LENMax parameter array length32nros-params
NROS_MAX_BYTE_ARRAY_LENMax byte array parameter length256nros-params
NROS_MAX_PARAM_DESCRIPTION_LENMax parameter description length; longer is truncated and logged, 0 = none (max 256)256nros-params