Skip to main content

Apex Topic Whitelist Configuration and Diagnostics

Updated: August 20, 2026 Applies to: Marvin Pro, Gento Skye, and Gento Luna Audience: customer developers, testers, and technical-support engineers

1. Purpose​

Apex uses several independent topic whitelists. They determine:

  • which topics can be written to customer recordings;
  • which topics can be loaded and published during playback;
  • which topics can be forwarded to the frontend through WebSocket;
  • which topics can be written to rolling diagnostic logs.

A topic appearing in ros2 topic list does not mean that it is automatically recorded, replayed, sent to the frontend, or included in a diagnostic bag.

This page has been updated for the current /tj interface rules as of August 20, 2026. Always verify the installed release and runtime parameters on the target controller. See the Marvin Pro ROS Topic List for the consolidated reference.

Scope and safety
  • Topic, parameter, and runtime-state queries are read-only.
  • Confirm the installed version and back up the original file before changing a whitelist, an installed file, or a systemd service.
  • Contact Gento Teleoperation Apex technical support when a release requires changes to a Python hard-coded whitelist. Customers should not edit installed Python files without confirmation.
  • Restarting services or replaying command topics can interrupt control or move the physical robot. Stop the robot, clear the workspace, and keep the emergency stop accessible.

2. Core Concepts​

2.1 A whitelist does not create a topic​

Adding a topic name only permits processing. It does not create a publisher or generate data. Processing normally requires all of the following:

  1. The topic name matches exactly, including case, leading slash, and namespace.
  2. The terminal, node, and publisher use the same ROS environment and ROS_DOMAIN_ID.
  3. The topic exists and continues publishing while recording or forwarding.
  4. The node can import the message type.
  5. Publisher and subscriber QoS settings are compatible.
  6. The topic is also selected for the current recording task.
  7. The storage path is writable and both the recorder and rosbag writer are healthy.

2.2 Whitelist versus selection list​

白名单:系统允许处理的最大范围
选择列表:本次任务从白名单中实际选择的子集

The whitelist defines the maximum permitted set. A task selection is a subset and cannot bypass the whitelist.

2.3 Topic names must match exactly​

/joint_states
/tj/joint_states
joint_states
/Joint_States

When APEX_ROS_NAMESPACE=tj is enabled, some relative names resolve under /tj/.... Some releases also contain absolute names or hard-coded sets, so inspect the actual target controller first:

source /etc/apex/apex_ros_env.sh
echo "ROS_DOMAIN_ID=${ROS_DOMAIN_ID:-未设置}"
echo "APEX_ROS_NAMESPACE=${APEX_ROS_NAMESPACE:-未设置}"
ros2 topic list -t | sort

3. Four Independent Whitelists​

WhitelistPurposeTypical nodeCurrent implementationTypical service
RecordingLimits topics written to customer recordingsdata_bag_recorderPython hard-coded set in the reviewed releaseapex-teleop.service
PlaybackLimits topics loaded and published from a bagplayback_nodeROS parameter topic_whitelistapex-teleop.service
WebSocketLimits ROS topics forwarded to the web frontendtopic_websocket_serverROS parameter with Python defaultsBackend/WebSocket module
Rolling diagnosticsLimits topics written to black-box diagnostic bagsall_topic_log_recorderPython hard-coded set in the reviewed releaseNormally starts with Robot

Service ownership may change between releases. Use systemctl cat, node lists, and process inspection before restarting anything.

4. Recording Whitelist​

4.1 Purpose and typical configuration​

The recording whitelist defines the maximum topic set shown to the frontend and accepted by the MCAP recorder.

Typical installed configuration path:

/opt/kernelmind/apex/install/recording_playback_nodes_py/share/recording_playback_nodes_py/config/recording_playback.yaml

Typical configuration:

data_bag_recorder:
ros__parameters:
allowed_topics:
- "/tj/joint_states"
- "/tj/info/gripper_feedback_L"
- "/tj/info/gripper_feedback_R"
- "/tj/info/eef_left"
- "/tj/info/eef_right"
- "/tj/control/joint_cmd_A"
- "/tj/control/joint_cmd_B"
- "/hand_left/joint_commands"
- "/hand_left/joint_states"
- "/hand_right/joint_commands"
- "/hand_right/joint_states"

4.2 Important limitation in the reviewed release​

The reviewed bag_recorder_data.py checks a Python ALLOWED_TOPICS constant and does not read allowed_topics from this YAML file:

只修改 recording_playback.yaml 中的 allowed_topics,不会让新 Topic 真正通过录制白名单。

Determine which implementation is installed:

source /etc/apex/apex_ros_env.sh

NODE=$(ros2 node list | grep '/data_bag_recorder$' | head -n 1)
echo "Recorder node: ${NODE:-未找到}"

if [ -n "$NODE" ]; then
ros2 param list "$NODE" | sort
ros2 param dump "$NODE"
fi

If allowed_topics appears, the release may support the YAML or ROS parameter. If it is absent, the recorder probably still uses a hard-coded set.

Locate the actual installed module:

find /opt/kernelmind/apex/install -type f -name 'bag_recorder_data.py' -print

Package names may include:

recording_playback_nodes_py
bag_recorder_nodes_py

4.3 Query topics currently accepted by the recorder​

Prefer the product recorder interface instead of reading YAML alone:

source /etc/apex/apex_ros_env.sh
ros2 service list -t | grep '/tj/recorder/control'

When the service type is marvin_msgs/srv/JsonCommand, query it directly:

source /etc/apex/apex_ros_env.sh

SERVICE=$(ros2 service list | grep '/tj/recorder/control$' | head -n 1)
echo "Recorder service: ${SERVICE:-未找到}"

if [ -n "$SERVICE" ]; then
ros2 service call "$SERVICE" marvin_msgs/srv/JsonCommand \
'{command_json: "{\"action\":\"get_topics\"}"}'
fi

The returned list contains topics that are currently visible, have an importable type, and pass the whitelist. It is not the complete ROS graph.

4.4 Selection for the current recording​

The start request can supply a topic list. The recorder intersects that list with the whitelist. Topics outside the whitelist are ignored.

Prefer starting recordings from the frontend. Direct service calls are intended for diagnostics.

Example selection:

source /etc/apex/apex_ros_env.sh

SERVICE=$(ros2 service list | grep '/tj/recorder/control$' | head -n 1)
ros2 service call "$SERVICE" marvin_msgs/srv/JsonCommand \
'{command_json: "{\"action\":\"start\",\"topics\":[\"/tj/joint_states\",\"/tj/info/gripper_feedback_L\",\"/tj/info/gripper_feedback_R\"]}"}'

Stop the recording:

source /etc/apex/apex_ros_env.sh

SERVICE=$(ros2 service list | grep '/tj/recorder/control$' | head -n 1)
ros2 service call "$SERVICE" marvin_msgs/srv/JsonCommand \
'{command_json: "{\"action\":\"stop\"}"}'

The preferred product implementation is:

声明 allowed_topics 参数
-> 读取参数为集合
-> 所有白名单判断使用该集合
-> 在 recording_playback.yaml 维护具体列表

This keeps the actual list in YAML and avoids editing installed Python packages.

If Gento Teleoperation Apex technical support confirms that a temporary hard-coded change is required:

  1. Record the installed package version.
  2. Back up the target Python file.
  3. Add only verified topic names.
  4. Restart the service that owns the recorder.
  5. Query get_topics and create a short validation recording.
  6. Move the change into a formal package because reinstalling or upgrading overwrites the patch.
Do not experiment on installed Python files

Editing site-packages is not a normal customer configuration method. An incorrect change can prevent the recorder from starting and will be lost after a reinstall or upgrade.

5. Playback Whitelist​

5.1 Purpose​

The playback whitelist controls which topics are loaded from a bag. A topic can exist in the bag but still be excluded from playback.

Typical configuration:

playback_node:
ros__parameters:
topic_whitelist:
- "/tj/joint_states"
- "/tj/info/gripper_feedback_L"
- "/tj/info/gripper_feedback_R"
- "/hand_left/joint_commands"
- "/hand_right/joint_commands"

The reviewed playback node declares and reads topic_whitelist, so YAML takes effect when the launch file loads the intended configuration.

5.2 Inspect the runtime value​

source /etc/apex/apex_ros_env.sh

NODE=$(ros2 node list | grep -E '/(bag_)?playback_node$' | head -n 1)
echo "Playback node: ${NODE:-未找到}"

if [ -n "$NODE" ]; then
ros2 param get "$NODE" topic_whitelist
fi

5.3 Notes​

  • In the reviewed release, an empty whitelist permits every topic. Do not set it empty casually.
  • Reload the bag after changing the whitelist.
  • The whitelist controls loading and publication; it does not switch the physical robot control source to Replay.
  • Replaying command topics can move the robot. Verify the control source, Ready state, workspace, and emergency stop.

6. WebSocket Frontend Whitelist​

6.1 Purpose​

topic_websocket_server serializes ROS messages to JSON and sends them to the web frontend. The main default set in the reviewed source is:

/tj/control/input_mode
/tj/info/arm_state
/tj/info/robot_state
/tj/info/vr_connected
/tj/joint_states

/tj/info/robot_info uses a separate subscription path and is not fully governed by the main set.

The default forwarding limit is approximately:

ROS Topic 为 200 Hz,不代表 Web 前端也会收到 200 Hz。

A 200 Hz ROS source therefore does not imply 200 Hz in the frontend.

6.2 Inspect runtime parameters​

source /etc/apex/apex_ros_env.sh

NODE=$(ros2 node list | grep '/topic_websocket_server$' | head -n 1)
echo "WebSocket node: ${NODE:-未找到}"

if [ -n "$NODE" ]; then
ros2 param get "$NODE" topic_whitelist
ros2 param get "$NODE" default_topic_fps
ros2 param get "$NODE" path
fi

6.3 Typical symptoms​

SymptomCheck first
ros2 topic echo has data but the frontend does notWebSocket whitelist, path, and client subscription
Frontend rate is much lower than ROSdefault_topic_fps or per-topic limiting
Whitelist topic not discovered yetExact name, node startup, ROS Domain, and namespace
WebSocket connects but only robot information appearsMain whitelist topics are missing or silent

Evaluate JSON serialization, CPU, network, and browser load before adding high-rate or large messages. Images and point clouds should not be added to the generic WebSocket whitelist merely because the frontend cannot see them.

7. Rolling Diagnostic Log Whitelist​

7.1 Purpose​

all_topic_log_recorder continuously records troubleshooting data as a rolling black box. It is separate from customer-initiated recording.

The reviewed default set is:

/tj/joint_states
/tj/info/gripper_feedback_L
/tj/info/gripper_feedback_R
/tj/info/eef_left
/tj/info/eef_right
/tj/control/eef_cmd_A
/tj/control/eef_cmd_B
/tj/control/enableL
/tj/control/enableR
/tj/control/gripperValueL
/tj/control/gripperValueR
/tj/control/ik_cmd_A
/tj/control/ik_cmd_B
/tj/control/ik_request
/tj/control/ik_result
/tj/control/joint_cmd_A
/tj/control/joint_cmd_B
/tj/control/joint_cmd_plan_A
/tj/control/joint_cmd_plan_B
/tj/control/qp_controller/joint_cmd_A
/tj/control/qp_controller/joint_cmd_B
/tj/control/playback_control
/tj/control/target_poseL
/tj/control/target_poseR
/hand_left/joint_commands
/hand_left/joint_states
/hand_right/joint_commands
/hand_right/joint_states

The list is also hard-coded in the reviewed Python source. Configurable parameters are:

log_storage_dir
max_log_bags
scan_interval_sec

Default log root:

~/.ros/log/topic_log-*

The default retention is ten SQLite3 log directories.

7.2 Inspect state​

source /etc/apex/apex_ros_env.sh

NODE=$(ros2 node list | grep '/all_topic_log_recorder$' | head -n 1)
echo "Log recorder node: ${NODE:-未找到}"

if [ -n "$NODE" ]; then
ros2 param dump "$NODE"
ros2 node info "$NODE"
fi

find "$HOME/.ros/log" -maxdepth 1 -type d -name 'topic_log-*' -printf '%TY-%Tm-%Td %TH:%TM %p\n' 2>/dev/null | sort

Do not add every system topic. High-rate feedback, images, point clouds, and verbose diagnostics can create substantial disk and system load.

8. Product-Line Differences​

8.1 Common Marvin Pro data​

/tj/joint_states
/tj/info/joint_feedback
/tj/info/eef_left
/tj/info/eef_right
/tj/info/gripper_feedback_L
/tj/info/gripper_feedback_R
/tj/control/joint_cmd_A
/tj/control/joint_cmd_B
/tj/control/gripperValueL
/tj/control/gripperValueR

8.2 Possible Gento Skye/Luna additions​

Gento may include body, head, waist, lift, or leg data in addition to both arms. Candidate names include:

/tj/control/joint_cmd_body
/tj/control/joint_cmd_head
/tj/control/qp_controller/joint_cmd_body
/tj/control/qp_controller/joint_cmd_head
/tj/info/robot_cmd_state
/tj/control/teleop/ik_request

These are candidates, not guaranteed interfaces. Inspect the target controller before adding anything:

source /etc/apex/apex_ros_env.sh
ros2 topic list -t | grep -E 'body|head|lift|robot_cmd_state|ik_request'

Skye and Luna have different body structures. Do not copy one body-topic set to the other without confirming type, meaning, and joint count.

9.1 Capture the current environment​

source /etc/apex/apex_ros_env.sh

echo '=== 系统与 ROS ==='
echo "ROS_DISTRO=${ROS_DISTRO:-未设置}"
echo "ROS_DOMAIN_ID=${ROS_DOMAIN_ID:-未设置}"
echo "APEX_ROS_NAMESPACE=${APEX_ROS_NAMESPACE:-未设置}"

echo '=== Apex 包版本 ==='
dpkg-query -W -f='${Package}\t${Version}\n' 2>/dev/null | \
grep -E '^(kernelmind-apex|apexteleop|kernelmind-apex-tool)' || true

echo '=== 白名单相关节点 ==='
ros2 node list | grep -E 'data_bag_recorder|playback_node|topic_websocket_server|all_topic_log_recorder' || true

9.2 Back up the configuration​

CFG=/opt/kernelmind/apex/install/recording_playback_nodes_py/share/recording_playback_nodes_py/config/recording_playback.yaml
sudo cp "$CFG" "$CFG.bak.$(date +%Y%m%d_%H%M%S)"

If the path differs, locate it first:

find /opt/kernelmind/apex/install -path '*/config/recording_playback.yaml' -print

9.3 Confirm whether the node reads the setting​

source /etc/apex/apex_ros_env.sh

for suffix in data_bag_recorder playback_node topic_websocket_server all_topic_log_recorder; do
NODE=$(ros2 node list | grep "/${suffix}$" | head -n 1)
echo
echo "=== ${suffix}: ${NODE:-未运行} ==="
if [ -n "$NODE" ]; then
ros2 param list "$NODE" | sort
fi
done

If the corresponding whitelist parameter is absent, do not assume that YAML controls the installed implementation.

9.4 Restart the actual owning service​

Service restart interrupts the current task

Stop teleoperation, recording, and playback before restarting a service. Do not run the following commands while the robot is moving.

Recording and playback normally start with Teleop:

sudo systemctl restart apex-teleop.service
systemctl --no-pager --full status apex-teleop.service

Rolling diagnostic recording normally starts with Robot:

sudo systemctl restart apex-robot.service
systemctl --no-pager --full status apex-robot.service

Confirm WebSocket ownership on the target release:

systemctl list-units --type=service --all | grep -E 'apex-(backend|web|teleop)'
pgrep -af 'topic_websocket_server'

10. Validation After a Change​

10.1 Validate the source topic​

Replace TOPIC with the topic under test:

source /etc/apex/apex_ros_env.sh
TOPIC=/tj/info/eef_left

ros2 topic info "$TOPIC" -v
timeout 5 ros2 topic echo "$TOPIC" --once
timeout 8 ros2 topic hz "$TOPIC"

Expected result: publisher count is greater than zero, one message can be received, and the observed rate is reasonable.

10.2 Confirm that the recorder lists the topic​

source /etc/apex/apex_ros_env.sh

SERVICE=$(ros2 service list | grep '/tj/recorder/control$' | head -n 1)
ros2 service call "$SERVICE" marvin_msgs/srv/JsonCommand \
'{command_json: "{\"action\":\"get_topics\"}"}'

10.3 Create a short recording and inspect the bag​

Use the frontend to record for 10 to 20 seconds while the target data changes. Locate the newest bag:

ROOT=${BAG_STORAGE_ROOT:-/media/$USER/BAG_STORAGE}
find "$ROOT" -type f -name metadata.yaml -printf '%T@ %h\n' 2>/dev/null | \
sort -nr | head

Inspect the selected bag:

ros2 bag info /实际/bag/data/目录

Verify the topic name, type, and message count. A listed topic with zero messages is not a successful recording.

10.4 Validate the playback whitelist​

Physical robot playback

Command-topic playback can move the physical robot. Prefer a no-motion environment for whitelist validation. Physical playback must follow the formal safety procedure with the emergency stop accessible.

source /etc/apex/apex_ros_env.sh

NODE=$(ros2 node list | grep -E '/(bag_)?playback_node$' | head -n 1)
ros2 param get "$NODE" topic_whitelist

Reload the bag before checking playback logs and output topics.

11. Quick Troubleshooting​

SymptomLikely causeAction
Topic exists in ROS but not in the recording listRecording whitelist, namespace mismatch, or unsupported typeQuery get_topics, exact names, and recorder logs
YAML change has no effectHard-coded recorder, wrong installed path, or launch did not load the YAMLInspect runtime parameters and installed implementation
Topic is selectable but absent from the bagNot selected, no data during recording, QoS mismatch, or write failureCheck status, echo, hz, logs, and ros2 bag info
Topic is in the bag but absent during playbackPlayback whitelist or bag was not reloadedInspect topic_whitelist and reload
ROS has data but frontend does notWebSocket whitelist, path mismatch, or client filteringInspect WebSocket parameters and logs
Frontend rate is near 30 HzWebSocket rate limitCheck default_topic_fps
/joint_states works but /tj/joint_states does notWhitelist and resolved name differUse the exact target topic name
CPU or disk load rises after adding a topicHigh rate, large messages, or duplicate recordingReduce scope and duration
Image topics make bags unexpectedly largeImage payload or separate MP4/WebRTC pathUse the product camera-recording path instead of adding every image topic

12. Configuration Principles​

  1. Add only topics required by the task.
  2. Prefer final feedback and final commands; add intermediate debug topics only when needed.
  3. Evaluate bandwidth and storage separately for images, point clouds, and high-rate arrays.
  4. Maintain separate Pro, Skye, and Luna sets.
  5. Validate the source topic, recorder interface, and actual bag after every change.
  6. Move field patches into a formal package before reinstalling or upgrading.
  7. A whitelist is a software filtering boundary, not a real-time performance guarantee.

13. Reviewed Source Conclusions​

As of the review baseline:

  • data_bag_recorder: recording whitelist is the ALLOWED_TOPICS constant in bag_recorder_data.py; the reviewed implementation does not read YAML allowed_topics.
  • playback_node: playback whitelist is read from the ROS parameter topic_whitelist.
  • topic_websocket_server: frontend whitelist is read from topic_whitelist, with a default forwarding limit of approximately 30 Hz.
  • all_topic_log_recorder: diagnostic whitelist is a Python ALLOWED_TOPICS constant.

Update this page whenever the implementation becomes parameterized, and retain the software version, product line, validation device, and validation date.