HEX FLOW NODE DATA
📖 Overview
What is hex_flow_node_data
hex_flow_node_data provides hex-flow nodes for recording and replaying robot data. It currently supports two operations: recording — subscribing to robot state, camera color, and camera depth topics, and writing them to Foxglove MCAP files via hex_util_data; and replay — reading MCAP files and publishing recorded data back onto the network. The record node is toggle-controlled by a boolean message on the record topic, enabling episode-based data collection.
What problem it solves
- Episode-based data collection: Supports multiple recording episodes, each written as a separate
episode_NNNNNN.mcapfile, making it easy to organize training data for imitation learning or model-based RL. - Dynamic topic discovery: Automatically classifies topics by suffix (
*state,*color,*depth) from theHEX_FLOW_REMAPJSON configuration, so the same binary works with any robot configuration — no code changes needed. - Foxglove-native format: Writes MCAP files compatible with Foxglove Studio for visualization and analysis.
- Flexible recording control: Start/stop recording via a dedicated
recordtopic; integrates with keyboard teleoperation or any other trigger source. - Integrated testing: Ships with a test node that publishes predefined control commands and toggles recording on the
Skey — no additional tools needed. - Simulation & real-robot support: Example launch configurations demonstrate integration with both MuJoCo simulation and real Archer Y6 robots with cameras.
Target users
- Engineers collecting demonstration data from HEXFELLOW robot systems for imitation learning or behavior cloning.
- Researchers running data acquisition pipelines (teleoperation → recording) before training policies.
- Developers building on the hex-flow framework who need a working data recording and replay layer.
Nodes
| Node | Description | Publishes | Subscribes |
|---|---|---|---|
hex-flow-data-record |
Records robot state and camera data to MCAP | — | {side}_arm_state, {side}_grip_state, obj_pose, {cam}_color, {cam}_depth, record |
hex-flow-data-record-test |
Terminal-based test control for recording | {side}_arm_ctrl, {side}_grip_ctrl, record |
keys |
hex-flow-data-replay |
Replays MCAP data back onto the network | {side}_arm_state, {side}_grip_state, obj_pose, {cam}_color, {cam}_depth |
— |
📦 Installation
Requirements
- Python >= 3.10
- OS: Ubuntu (or other Linux)
- Core dependencies:
hex_flow_core>= 0.0.0, < 0.1.0hex_util_data>= 0.0.0, < 0.1.0hex_util_msg>= 0.0.0, < 0.1.0hex_util_runtime>= 0.0.0, < 0.1.0hex_util_robot>= 0.0.0, < 0.1.0
Install hex-flow-cli
For Ubuntu or any Debian-based system, install Zenoh and hex-flow CLI:
sudo apt update
sudo apt install -y curl gpg
curl -L https://download.eclipse.org/zenoh/debian-repo/zenoh-public-key | sudo gpg --dearmor --yes --output /etc/apt/keyrings/zenoh-public-key.gpg
echo "deb [signed-by=/etc/apt/keyrings/zenoh-public-key.gpg] https://download.eclipse.org/zenoh/debian-repo/ /" | sudo tee -a /etc/apt/sources.list > /dev/null
sudo apt update
sudo apt install zenoh curl
curl -fsSL https://raw.githubusercontent.com/hexfellow/hex-flow/main/install.sh | sh
For other systems, please install zenohd yourself, then run the install script.
Install hex-flow-node-data from PyPI
pip install hex_flow_node_data
Install hex-flow-node-data from source
We provide a venv.sh script to create a virtual environment with all dependencies installed. However, you need to install uv first. For uv installation, please refer to uv official installation guide.
curl -LsSf https://astral.sh/uv/install.sh | sh
Then you can use venv.sh to create a virtual environment with all dependencies installed:
git clone https://github.com/hexfellow/hex_flow_node_data.git
cd hex_flow_node_data
./venv.sh
📑 Python Config API
The package provides helper functions that return NodeConfig objects for easy integration into your LaunchConfig.
from hex_flow_core import LaunchConfig
from hex_flow_node_data import (
default_data_record_node,
default_data_record_test_node,
default_data_replay_node,
)
default_data_record_node
| Parameter | Type | Default | Description |
|---|---|---|---|
name |
str |
"data_record" |
Node name |
record_path |
str |
"./hex_record_data" |
Directory path for MCAP file output |
foxglove_host |
str |
"127.0.0.1" |
Foxglove WebSocket server host |
foxglove_port |
int |
8765 |
Foxglove WebSocket server port |
start_cnt |
int |
0 |
Starting episode count for file naming |
required |
bool |
True |
Required for launch |
hidden |
bool |
False |
Hidden from TUI display |
remap_dict |
dict |
None |
Custom remap; auto-generated if None |
sensor_source |
str |
"mujoco_e3_desktop" |
Sensor node name for auto-remap topic prefix |
default_data_record_test_node
| Parameter | Type | Default | Description |
|---|---|---|---|
name |
str |
"data_record_test" |
Node name |
rate_hz |
float |
10.0 |
Control command publish rate (Hz) |
arm_ctrl_mode |
str |
"pos" |
Arm control mode ("mit", "pos") |
grip_ctrl_mode |
str |
"pos" |
Gripper control mode ("mit", "pos") |
required |
bool |
False |
Required for launch |
hidden |
bool |
False |
Hidden from TUI display |
remap_dict |
dict |
None |
Custom remap; auto-generated if None |
sensor_source |
str |
"mujoco_e3_desktop" |
Sensor node name for auto-remap of control topics |
keys_source |
str |
"teleop_keyboard" |
Keyboard node name for auto-remap of keys topic |
default_data_replay_node
| Parameter | Type | Default | Description |
|---|---|---|---|
name |
str |
"data_replay" |
Node name |
mcap_path |
str |
"~/hex_record_data" |
Path to MCAP file or directory |
enable_color |
bool |
False |
Enable color image replay |
enable_depth |
bool |
False |
Enable depth image replay |
color_encoding |
str |
"bgr8" |
Color image encoding |
depth_encoding |
str |
"mono16" |
Depth image encoding |
rate_hz |
float |
500.0 |
Replay publish rate (Hz) |
state_topics |
list |
["left_arm_state", "right_arm_state", "left_grip_state", "right_grip_state", "obj_pose"] |
State topic names to replay |
color_topics |
list |
["head_color"] |
Color image topic names to replay |
depth_topics |
list |
["head_depth"] |
Depth image topic names to replay |
required |
bool |
True |
Required for launch |
hidden |
bool |
False |
Hidden from TUI display |
remap_dict |
dict |
None |
Custom remap; auto-generated if None |
💡 Examples
Ready-to-run config scripts are provided in the example/ directory. Each script prints a launch YAML to stdout, intended for use with hexflow run:
Simulation-based recording (E3 Desktop)
# Records robot state and camera data from a simulated E3 Desktop
# Toggle recording with the S key (keyboard teleoperation)
hexflow run example/sim_record_test.launch.py
Real-robot recording (Dual Archer Y6)
# Records robot state and camera data from real Archer Y6 arms
# with Berxel depth camera and USB cameras
hexflow run example/real_record_test.launch.py
YAML Examples
Simulated recording (E3 Desktop)
nodes:
- name: data_record
build: pip install hex_flow_node_data
run: hex-flow-data-record
required: false
hidden: true
remap:
left_arm_state: mujoco_e3_desktop/left_arm_state
right_arm_state: mujoco_e3_desktop/right_arm_state
left_grip_state: mujoco_e3_desktop/left_grip_state
right_grip_state: mujoco_e3_desktop/right_grip_state
head_color: mujoco_e3_desktop/head_color
left_color: mujoco_e3_desktop/left_color
right_color: mujoco_e3_desktop/right_color
head_depth: mujoco_e3_desktop/head_depth
left_depth: mujoco_e3_desktop/left_depth
right_depth: mujoco_e3_desktop/right_depth
record: data_record_test/record
env:
RECORD_PATH: "./record_data"
FOXGLOVE_HOST: "127.0.0.1"
FOXGLOVE_PORT: "8765"
START_CNT: "0"
- name: data_record_test
build: pip install hex_flow_node_data
run: hex-flow-data-record-test
required: true
hidden: true
remap:
left_arm_ctrl: mujoco_e3_desktop/left_arm_ctrl
right_arm_ctrl: mujoco_e3_desktop/right_arm_ctrl
left_grip_ctrl: mujoco_e3_desktop/left_grip_ctrl
right_grip_ctrl: mujoco_e3_desktop/right_grip_ctrl
record: data_record_test/record
keys: teleop_keyboard/teleop_keyboard
env:
RATE_HZ: "100"
ARM_CTRL_MODE: "pos"
GRIP_CTRL_MODE: "pos"
Real-robot recording (Dual Archer Y6)
nodes:
- name: data_record
build: pip install hex_flow_node_data
run: hex-flow-data-record
required: false
hidden: true
remap:
left_arm_state: left_archer_y6/arm_state
right_arm_state: right_archer_y6/arm_state
left_grip_state: left_archer_y6/grip_state
right_grip_state: right_archer_y6/grip_state
head_color: head_berxel/color
head_depth: head_berxel/depth
left_color: left_cam_usb/color
record: data_record_test/record
env:
RECORD_PATH: "./record_data"
FOXGLOVE_HOST: "127.0.0.1"
FOXGLOVE_PORT: "8765"
START_CNT: "0"
- name: data_record_test
build: pip install hex_flow_node_data
run: hex-flow-data-record-test
required: true
hidden: true
remap:
left_arm_ctrl: left_archer_y6/arm_ctrl
right_arm_ctrl: right_archer_y6/arm_ctrl
left_grip_ctrl: left_archer_y6/grip_ctrl
right_grip_ctrl: right_archer_y6/grip_ctrl
record: data_record_test/record
keys: teleop_keyboard/teleop_keyboard
env:
RATE_HZ: "100"
ARM_CTRL_MODE: "pos"
GRIP_CTRL_MODE: "pos"
Topics
Record Node — Subscribed Topics
The record node discovers topics dynamically from the HEX_FLOW_REMAP JSON env var, classifying by suffix:
| Suffix | Message Type | Description |
|---|---|---|
*state |
HexArmState / HexGripState / HexPoseState |
Robot joint/pose state |
*color |
HexImgSimple (encoding bgr8) |
Color camera frames |
*depth |
HexImgSimple (encoding mono16) |
Depth camera frames |
record |
raw bytes (1-byte boolean) | Start/stop recording (non-zero = start) |
State topics — HexArmState
| Field | Type | Description |
|---|---|---|
ts_ns |
int64 |
Timestamp in nanoseconds |
jnt_pos |
[float64] |
Joint position array |
jnt_vel |
[float64] |
Joint velocity array |
jnt_eff |
[float64] |
Joint effort/torque array |
pose_pos |
[float64] |
End-effector position (x, y, z) |
pose_quat |
[float64] |
End-effector orientation (w, x, y, z) |
Schema: msgs/msg_robot/arm_state.fbs
State topics — HexGripState
| Field | Type | Description |
|---|---|---|
ts_ns |
int64 |
Timestamp in nanoseconds |
jnt_pos |
[float64] |
Gripper joint position |
jnt_vel |
[float64] |
Gripper joint velocity |
jnt_eff |
[float64] |
Gripper joint effort |
Schema: msgs/msg_robot/grip_state.fbs
State topics — HexPoseState
| Field | Type | Description |
|---|---|---|
ts_ns |
int64 |
Timestamp in nanoseconds |
pose_pos |
[float64] |
Object position (x, y, z) |
pose_quat |
[float64] |
Object orientation (w, x, y, z) |
Schema: msgs/msg_robot/pose_state.fbs
Camera topics — HexImgSimple
| Field | Type | Description |
|---|---|---|
ts_ns |
int64 |
Timestamp in nanoseconds |
encoding |
HexImgEncoding |
Image encoding (bgr8 or mono16) |
width |
uint16 |
Image width |
height |
uint16 |
Image height |
data |
[uint8] |
Raw image pixel data (flattened) |
Schema: msgs/msg_image/img_simple.fbs
Record Test Node — Published Topics
| Topic | Message Type | Description |
|---|---|---|
{side}_arm_ctrl |
HexArmCtrl |
Arm control command |
{side}_grip_ctrl |
HexGripCtrl |
Gripper control command |
record |
raw bytes (1-byte boolean) | Start/stop recording command |
{side}_arm_ctrl — HexArmCtrl
| Field | Type | Description |
|---|---|---|
ts_ns |
int64 |
Timestamp in nanoseconds |
ctrl_mode |
HexArmCtrlMode |
Control mode enum (mit=0, pos=2) |
jnt_pos |
[float64] |
Joint position target |
jnt_vel |
[float64] |
Joint velocity target |
jnt_eff |
[float64] |
Joint effort target |
mit_tau |
[float64] |
MIT mode torque feedforward |
mit_kp |
[float64] |
MIT mode stiffness gains |
mit_kd |
[float64] |
MIT mode damping gains |
lim_err |
[float64] |
Position error limit for safety |
Schema: msgs/msg_robot/arm_ctrl.fbs
{side}_grip_ctrl — HexGripCtrl
| Field | Type | Description |
|---|---|---|
ts_ns |
int64 |
Timestamp in nanoseconds |
ctrl_mode |
HexGripCtrlMode |
Control mode enum (mit=0, pos=2) |
jnt_pos |
[float64] |
Gripper joint position target |
jnt_vel |
[float64] |
Gripper joint velocity target |
jnt_eff |
[float64] |
Gripper joint effort target |
mit_tau |
[float64] |
MIT mode torque feedforward |
mit_kp |
[float64] |
MIT mode stiffness gains |
mit_kd |
[float64] |
MIT mode damping gains |
lim_err |
[float64] |
Position error limit for safety |
Schema: msgs/msg_robot/grip_ctrl.fbs
Environment Variables
All Nodes
| Variable | Type | Default | Description |
|---|---|---|---|
HEX_FLOW_NODE_NAME |
str |
constructor arg | Overrides node name (handled by hex_flow_core) |
HEX_FLOW_REMAP |
str |
{} |
JSON dict for topic remapping (handled by hex_flow_core) |
RUST_LOG |
str |
info |
Log level for envlog |
Record Node (hex-flow-data-record)
| Variable | Type | Default | Description |
|---|---|---|---|
RECORD_PATH |
str |
"../hex_record_data" |
Directory path for MCAP file output |
FOXGLOVE_HOST |
str |
"127.0.0.1" |
Foxglove WebSocket server host |
FOXGLOVE_PORT |
int |
8765 |
Foxglove WebSocket server port |
START_CNT |
int |
0 |
Starting episode count for file naming |
Record Test Node (hex-flow-data-record-test)
| Variable | Type | Default | Description |
|---|---|---|---|
RATE_HZ |
float |
10.0 |
Control command publish rate (Hz) |
ARM_CTRL_MODE |
str |
"pos" |
Arm control mode ("mit", "pos") |
GRIP_CTRL_MODE |
str |
"pos" |
Gripper control mode ("mit", "pos") |
Replay Node (hex-flow-data-replay)
| Variable | Type | Default | Description |
|---|---|---|---|
MCAP_PATH |
str |
"~/hex_record_data" |
Path to MCAP file or directory |
ENABLE_COLOR |
bool |
false |
Enable color image replay |
ENABLE_DEPTH |
bool |
false |
Enable depth image replay |
COLOR_ENCODING |
str |
"bgr8" |
Color image encoding |
DEPTH_ENCODING |
str |
"mono16" |
Depth image encoding |
RATE_HZ |
float |
500.0 |
Replay publish rate (Hz) |
Architecture
The data recording pipeline follows a modular, decoupled design:
-
Dynamic topic discovery — The record node reads the
HEX_FLOW_REMAPJSON environment variable at startup and classifies all remapped topics by their suffix:*statetopics (arm/gripper/pose states),*colortopics (color camera images), and*depthtopics (depth camera images). This allows the same binary to work with any robot configuration. -
Type-specific callbacks — For each discovered topic, the node creates a dedicated callback that subscribes via
hex_flow_core.Node.create_sub(). State topics are parsed usingparse_hex_arm_state,parse_hex_grip_state, orparse_hex_pose_state; image topics useparse_color_msgandparse_depth_msg. All parsed data is forwarded to aHexMcapWriterinstance connected to a Foxglove WebSocket server. -
Episode-based recording — The node listens on the
recordtopic for a single-byte boolean payload. On a rising edge (non-zero byte), it starts a new recording episode — incrementing the episode counter and creating a newepisode_NNNNNN.mcapfile at the configuredRECORD_PATH. On a falling edge (zero byte), it stops the current episode. This enables seamless episode-level data collection. -
MCAP output format — Data is written to Foxglove MCAP files, a standard robotics binary log format that supports schemas, multiple topics, and efficient streaming. MCAP files can be visualized directly in Foxglove Studio for inspection and analysis.
-
Decoupled test node — The
hex-flow-data-record-testnode is an independent process that publishes constant arm and gripper control commands at a configurable rate. It also listens for keyboard events and toggles therecordtopic when theSkey is pressed (with rising-edge detection to avoid double-toggle). This provides a complete recording pipeline that works with both simulation (sim_record_test.launch.py) and real hardware (real_record_test.launch.py).
This decoupling allows the high-frequency control loop to run independently from the recording system, ensuring that data collection does not interfere with real-time control.
📄 License
Apache License 2.0. See LICENSE.
🌟 Star History
👥 Contributors
Metadata
Release files for hex-flow-node-data 0.0.2.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| hex_flow_node_data-0.0.2.1.tar.gz | 20.1 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| hex_flow_node_data-0.0.2.1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 36.0 kB
Release files / hex_flow_node_data-0.0.2.1.tar.gz
| Download URL | hex_flow_node_data-0.0.2.1.tar.gz |
|---|---|
| Size | 20.1 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
0fb47ac9ff6cfefa8dd3f29d607f2856799bdafeb0db663d7c46a690cbed0b35
|
|
BLAKE2b-256 checksum How to use checksums |
5eb0f9990c41698eff9ddc0afc8d8d9056656e5e326f685baa1c281dd5528d99
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.10.12
|
Release files / hex_flow_node_data-0.0.2.1-py3-none-any.whl
| Download URL | hex_flow_node_data-0.0.2.1-py3-none-any.whl |
|---|---|
| Size | 16.0 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
bc92f1afe297ad12f4431c76fee01fd29826f54b112f8e96101211a71b2cc730
|
|
BLAKE2b-256 checksum How to use checksums |
e76c34997735ab3d2d1e719afc8eb6d96b08ed1f0efb01e0486a9723413bc816
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.10.12
|