Hex Flow Node for Data Recording and Replaying
Project description
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
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file hex_flow_node_data-0.0.2.1.tar.gz.
File metadata
- Download URL: hex_flow_node_data-0.0.2.1.tar.gz
- Upload date:
- Size: 20.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.10.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
0fb47ac9ff6cfefa8dd3f29d607f2856799bdafeb0db663d7c46a690cbed0b35
|
|
| MD5 |
7ae30ae5142fdb12716fb911730cb9fa
|
|
| BLAKE2b-256 |
5eb0f9990c41698eff9ddc0afc8d8d9056656e5e326f685baa1c281dd5528d99
|
File details
Details for the file hex_flow_node_data-0.0.2.1-py3-none-any.whl.
File metadata
- Download URL: hex_flow_node_data-0.0.2.1-py3-none-any.whl
- Upload date:
- Size: 16.0 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.10.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
bc92f1afe297ad12f4431c76fee01fd29826f54b112f8e96101211a71b2cc730
|
|
| MD5 |
6d5b9e2176dd97ed9d0435dfd7864ada
|
|
| BLAKE2b-256 |
e76c34997735ab3d2d1e719afc8eb6d96b08ed1f0efb01e0486a9723413bc816
|