RFrame Deployment Guide
Documentation entry point: Getting Started with RFrame.
1. Scope
This guide explains:
- What to install on the target machine.
- How to manage global
rframe.jsonseparately from application Channel JSON. - How to start an application with its configuration.
- How to validate a completed deployment.
For CMake and source builds, see the RFrame Build Guide. For C++ API implementation, see the RFrame Development Guide.
2. Supported capabilities
This guide covers deployment of:
- Logging.
AppCore;- Basic
ChannelManagerusage. HybridChannel;HybridRpcChannel。
Example project: the robby-r-frame-example deb package, installed at /opt/robby/RFrameExample/.
3. Install deployment packages
3.1. Check the environment
cat /etc/os-release
dpkg --print-architecture
If the Hybrid configuration enables ROS 2:
source /opt/ros/humble/setup.bash
echo "$ROS_DISTRO"
For custom ROS 2 messages or services, also source the corresponding workspace:
source /path/to/message_workspace/install/setup.bash
3.2. Install pinned versions
sudo apt-get update
apt-cache policy r-frame r-frame-plugin
apt-cache madison r-frame
RFRAME_VERSION='<verified-version>'
sudo apt-get install -y --no-install-recommends \
"r-frame=${RFRAME_VERSION}"
JSON channel configuration (recommended) requires r-frame-plugin, which provides JsonDynamicDataPlugin, the JSON parsing capability used by ChannelConfigLoader:
PLUGIN_VERSION='<version-compatible-with-RFrame>'
sudo apt-get install -y --no-install-recommends \
"r-frame-plugin=${PLUGIN_VERSION}"
This package also supplies remote backends such as ROS 2, zenoh, and WebSocket. Verify JSON parsing availability:
grep JsonDynamicDataPlugin /opt/robby/r-frame/config/plugins.json
r-frame and r-frame-plugin must be compatible packages from the same SDK release build.
3.3. Install Python wheels
The r-frame deb includes native libraries and Python bindings:
- System Python bindings are installed in
/usr/lib/python3/dist-packages. - Wheels from the same build are retained in
/usr/local/lib/rframe/*.whlfor virtual environments or custom Python. - The
r-frame-pluginPython ROS 2 provider wheel is/usr/local/lib/rframe-plugin/rframe_plugin_ros2_python-*.whl, imported asrframe_ros2. Install it separately when using this provider.
For system Python, verify directly after installing the deb; no extra pip installation is needed:
/usr/bin/python3 -c 'import rframe; print(rframe.__file__)'
For a virtual environment, install the wheel bundled with the deb:
python3 -m venv --system-site-packages /opt/<app>/venv
source /opt/<app>/venv/bin/activate
ls /usr/local/lib/rframe/*.whl
python -m pip install --no-deps /usr/local/lib/rframe/rframe-*.whl
python -m pip install --no-deps /usr/local/lib/rframe-plugin/rframe_plugin_ros2_python-*.whl
python -c 'import rframe; print(rframe.__version__, rframe.__build_tag__)'
dpkg-query -W -f='${Version}\n' r-frame
--system-site-packages allows access to ROS 2 Python modules installed through system packages; omit it if ROS 2 is not used. Wheels provide only Python bindings and still require native libraries from the matching r-frame deb at runtime. Do not distribute wheels alone or mix deb and wheel packages from different RFrame release builds.
For custom Python, such as /opt/py310/bin/python3, use that interpreter's pip. After installing both deb packages above, run:
sudo /opt/py310/bin/python3 -m pip install --no-deps /usr/local/lib/rframe/rframe-*.whl
sudo /opt/py310/bin/python3 -m pip install --no-deps /usr/local/lib/rframe-plugin/rframe_plugin_ros2_python-*.whl
For ROS 2, the Python minor version must match the rclpy extension. For example, Python 3.12 cannot load a CPython 3.10 rclpy extension. Check actual import paths after installation:
/opt/py310/bin/python3 -c 'import rframe, rframe_ros2; print(rframe.__file__); print(rframe_ros2.__file__)'
rframe_ros2 is an optional provider for application-owned rclpy nodes/executors. Installing the wheel does not enable it automatically, and it does not replace Hybrid SHM channels. Registration through rframe_ros2.install() requires core support for rframe.channel_provider.register_channel_provider and ChannelManager.create_with_provider. Successful import alone does not establish compatibility. The rc51 core is confirmed not to provide this interface; use a core version supporting the provider API.
4. Deployment directory
/opt/<app>/
├── bin/ # Application executables
├── config/
│ ├── rframe.json # Global RFrame configuration (logging)
│ └── channels.json # Channel configuration loaded by the application
├── lib/ # Private application libraries, if any
└── VERSION # Application, RFrame, and plugin versions
Record installed versions and dynamic-library resolution:
dpkg-query -W r-frame r-frame-plugin 2>/dev/null
ldd /opt/<app>/bin/<app>
5. Global RFrame configuration: rframe.json
5.1. File lookup order
RFrame selects the first existing main configuration in this order:
$RFRAME_CONFIG_PATH;./rframe.json;~/.config/rframe/rframe.json;/etc/rframe/rframe.json。
For production, specify it explicitly:
export RFRAME_CONFIG_PATH=/opt/<app>/config/rframe.json
Set this before the application calls AppCore::init(). Do not switch to another file during execution.
5.2. User configuration
Global rframe.json configures only the log level:
{
"log": {
"level": "info"
}
}
Only the logging section is exposed in global configuration:
| Section | Loader | Purpose |
|---|---|---|
log | AppCore / GlobalConfig | Framework log level |
Other framework settings are managed by the SDK and installation packages, not exposed as user configuration.
Do not put Channel configuration in global rframe.json. Applications explicitly load it at runtime from separate JSON files or strings.
5.3. Configuration precedence
log.level supports trace, debug, info, warn, error, and off; the default is info.
Precedence:
RFRAME_LOG_LEVEL > rframe.json > framework defaults
To override the log level temporarily:
export RFRAME_LOG_LEVEL=debug
6. Write Channel JSON
Store Channel configuration in an application-owned JSON file, such as /opt/<app>/config/channels.json:
{
"channels": {
"instance_name": {
"type": "hybrid"
}
}
}
Keys under channels are instance names used by ChannelManager, not topic or service names.
6.1. HybridChannel:SHM-only
{
"channels": {
"local_reader": {
"type": "hybrid",
"topic": "/example/local",
"handler": "reader",
"hybrid": {
"enable_shm": true,
"enable_remote": false,
"auto_route": false
},
"shm": {
"memory_size": 65536,
"type_name": "std_msgs/msg/String"
}
}
}
}
SHM-only configuration does not need a ros2 object. memory_size must be numeric. queue_size defaults to 10; specify it only for a nondefault value.
6.2. HybridChannel:SHM + ROS 2
This example converts the head-camera compressed-image subscription into a loader-readable configuration:
{
"channels": {
"head_color_reader": {
"type": "hybrid",
"topic": "/robby/sensors/camera/head/color/compressed",
"handler": "reader",
"hybrid": {
"enable_shm": true,
"enable_remote": true,
"auto_route": false
},
"shm": {
"memory_size": 5242880,
"type_name": "sensor_msgs/msg/CompressedImage"
},
"ros2": {
"type_name": "sensor_msgs/msg/CompressedImage",
"qos": {
"reliability": "best_effort"
}
}
}
}
}
Interface source: RobbySensorCenter Camera Topics.
Configuration rules:
typemust behybrid.handlerisreader,writer, ordual.- The common
topicis passed to enabled subchannels. - New configurations use
enable_remote, which maps to the same ABI field as legacyenable_ros2. - Provide a child object for each enabled backend.
- Put ROS 2 QoS under
ros2.qos, specifying only nondefault values such asreliability: best_effort. - Omit framework defaults such as
require_all=falseand SHM-priority deduplication. - Do not include the legacy compatibility field
hybrid.dedup.require_all=truemeans the entire open operation fails if any enabled backend fails to open.
For ROS 2 only, set enable_shm to false and remove the shm object.
6.3. HybridRpcChannel:SHM-only
{
"channels": {
"calculator_rpc": {
"type": "hybrid_rpc",
"hybrid_rpc": {
"service_prefix": "/example/calculator",
"enable_shm": true,
"enable_ros2": false,
"auto_route": false
}
}
}
}
6.4. HybridRpcChannel:SHM + ROS 2
{
"channels": {
"calculator_rpc": {
"type": "hybrid_rpc",
"hybrid_rpc": {
"service_prefix": "/example/calculator",
"enable_shm": true,
"enable_ros2": true
},
"ros2": {
"service_prefix": "/example/calculator",
"service_type": "example_interfaces/srv/AddTwoInts",
"default_timeout_ms": 3000
}
}
}
}
ros2.default_timeout_ms defaults to 2000 ms. The example explicitly uses 3000 ms to match the hybrid_rpc-level default; omitting it leaves this level at 2000 ms.
Hybrid RPC does not use topic or handler. hybrid_rpc.service_prefix must match ros2.service_prefix, and client/server must use the same service type.
6.5. Load Channel JSON
| Configuration source | Use case | Loading API |
|---|---|---|
Standalone channels.json | File-based deployment or switching between configurations | loadFromFile() / loadByName() |
| JSON string | Configuration service delivery or testing | loadFromString() / loadSingleChannel() |
Keep the outer {"channels": {...}} object in production Channel configuration. After loading, pass the resulting MsgChannelConfig to ChannelManager::createChannel(). See the RFrame Development Guide for code.
7. Start the application
source /opt/ros/humble/setup.bash # When ROS 2 is enabled
source /path/to/message_workspace/install/setup.bash # For custom types
export RFRAME_CONFIG_PATH=/opt/<app>/config/rframe.json
exec /opt/<app>/bin/<app>
Python applications use the same environment variables:
source /opt/ros/humble/setup.bash # When ROS 2 is enabled
source /path/to/message_workspace/install/setup.bash # For custom types
export RFRAME_CONFIG_PATH=/opt/<app>/config/rframe.json
python3 -u /opt/<app>/bin/app.py
Before deployment, verify that Python bindings can be imported:
python3 -c 'import rframe; print(rframe.__file__)'
Application lifecycle order:
AppCore::init()
→ Application loads channels.json or a JSON string
→ ChannelManager creates Channels
→ Execute application logic
→ AppCore::shutdown()
→ ChannelManager cleans up all managed Channels
See the RFrame Development Guide for C++ implementation.
8. Validate configuration
The configuration checker is part of the example deb's standalone channel unit. Build it once:
sudo apt install robby-r-frame-example
cmake -S /opt/robby/RFrameExample/src/channel -B /tmp/rfe-channel
cmake --build /tmp/rfe-channel -j4 --target channel_config_json_example
Then check the deployed channels configuration:
/tmp/rfe-channel/channel_config_json_example /opt/<app>/config/channels.json
Check the instance count, type, valid, topic, handler, enabled backends, and timeout. Then open the target Channel by name:
/tmp/rfe-channel/channel_config_json_example \
/opt/<app>/config/channels.json head_color_reader
See the RFrame Build Guide for building the checker.