DexHand Logger

The DexHand logger module provides data logging and analysis capabilities for hand operation.

Core Components

Log Entry Types

class pyzlg_dexhand.dexhand_logger.LogEntry(timestamp, hand, entry_type)[source]

Base class for log entries

entry_type: str
hand: str
timestamp: float
class pyzlg_dexhand.dexhand_logger.CommandLogEntry(timestamp, hand, entry_type, command_type, joint_commands, control_mode)[source]

Log entry for a hand command

command_type: str
control_mode: ControlMode
joint_commands: Dict[str, float]
class pyzlg_dexhand.dexhand_logger.FeedbackLogEntry(timestamp, hand, entry_type, joints, tactile)[source]

Log entry for hand feedback

joints: Dict[str, JointFeedback]
tactile: Dict[str, StampedTactileFeedback]

Logger Classes

Main Logger

class pyzlg_dexhand.dexhand_logger.DexHandLogger(log_dir='dexhand_logs')[source]

Logger for dexterous hand commands and feedback with background writing

__init__(log_dir='dexhand_logs')[source]

Initialize hand logger

Parameters:

log_dir (str) – Directory to store log files

close()[source]

Close the logger and save any remaining data

log_command(command_type, joint_commands, control_mode, hand, feedback=None)[source]

Log a command without blocking

Parameters:
  • command_type (str) – Type of command (move_joints, reset_joints, etc)

  • joint_commands (Dict[str, float]) – Dictionary of joint name to commanded position

  • control_mode (ControlMode) – Control mode used

  • hand (str) – Which hand (‘left’ or ‘right’)

  • feedback (Optional[HandFeedback]) – Optional HandFeedback if feedback was collected

log_feedback(feedback, hand)[source]

Log feedback without blocking

Parameters:
  • feedback (HandFeedback) – HandFeedback from polling

  • hand (str) – Which hand (‘left’ or ‘right’)

plot_session(hands=None, show=True, save=True)[source]

Plot command and feedback data from the session

This method should be called outside the control loop, typically during analysis or after the session.

Parameters:
  • hands (Optional[List[str]]) – Which hands to plot (‘left’, ‘right’, or both)

  • show (bool) – Whether to show plots interactively

  • save (bool) – Whether to save plots to files

save_metadata(metadata)[source]

Save session metadata

Parameters:

metadata (Dict[str, Any]) – Dictionary of metadata to save

Background Writer

class pyzlg_dexhand.dexhand_logger.LogWriter(session_dir)[source]

Background thread for writing log entries to files

__init__(session_dir)[source]

This constructor should always be called with keyword arguments. Arguments are:

group should be None; reserved for future extension when a ThreadGroup class is implemented.

target is the callable object to be invoked by the run() method. Defaults to None, meaning nothing is called.

name is the thread name. By default, a unique name is constructed of the form “Thread-N” where N is a small decimal number.

args is a list or tuple of arguments for the target invocation. Defaults to ().

kwargs is a dictionary of keyword arguments for the target invocation. Defaults to {}.

If a subclass overrides the constructor, it must make sure to invoke the base class constructor (Thread.__init__()) before doing anything else to the thread.

run()[source]

Process log entries from queue

stop()[source]

Stop the writer thread and close files

Examples

Basic Logging

from pyzlg_dexhand import DexHandLogger, ControlMode

# Initialize logger
logger = DexHandLogger(log_dir="dexhand_logs")

# Log a command
logger.log_command(
    command_type="move_joints",
    joint_commands={"th_rot": 30, "th_mcp": 45},
    control_mode=ControlMode.CASCADED_PID,
    hand="right"
)

# Log feedback
logger.log_feedback(feedback_data, hand="right")

# Save session metadata
logger.save_metadata({
    "operator": "user1",
    "experiment": "grasp_test",
    "conditions": "normal"
})

# Generate plots and close
logger.plot_session(show=False, save=True)
logger.close()

Visualization

# Plot specific hands
logger.plot_session(
    hands=["right"],
    show=True,
    save=True
)

Analysis

# Get session statistics
with logger.buffer_lock:
    cmd_count = len(logger.command_buffers["right"])
    fb_count = len(logger.feedback_buffers["right"])
    print(f"Commands: {cmd_count}, Feedback: {fb_count}")

Log File Structure

Directory Layout

Each logging session creates a timestamped directory:

dexhand_logs/
└── YYYYMMDD_HHMMSS/
    ├── metadata.json
    ├── left_commands.jsonl
    ├── left_feedback.jsonl
    ├── right_commands.jsonl
    ├── right_feedback.jsonl
    ├── left_joints.png
    ├── left_tactile.png
    ├── right_joints.png
    └── right_tactile.png

File Formats

Command Log (JSONL):

{
    "timestamp": 1234567890.123,
    "hand": "right",
    "entry_type": "command",
    "command_type": "move_joints",
    "joint_commands": {
        "th_rot": 30.0,
        "th_mcp": 45.0
    },
    "control_mode": "CASCADED_PID"
}

Feedback Log (JSONL):

{
    "timestamp": 1234567890.123,
    "hand": "right",
    "entry_type": "feedback",
    "joints": {
        "th_rot": {
            "timestamp": 1234567890.123,
            "angle": 30.0,
            "encoder_position": 1000
        }
    },
    "tactile": {
        "th": {
            "timestamp": 1234567890.123,
            "normal_force": 1.5,
            "tangential_force": 0.5
        }
    }
}

Metadata (JSON):

{
    "timestamp": "2024-01-01T12:00:00",
    "statistics": {
        "duration": 60.0,
        "num_commands": {
            "right": 100
        },
        "num_feedback": {
            "right": 500
        }
    },
    "experiment_info": {
        "operator": "user1",
        "conditions": "normal"
    }
}

Visualization

Joint Plots

  • Command vs actual joint angles over time

  • Tracking error analysis

  • Multiple joints overlaid for comparison

Tactile Plots

  • Normal and tangential forces over time

  • Force vector visualization

  • Contact location heatmaps

Notes

Thread Safety

  • Uses background thread for file writing

  • Thread-safe buffers for data access

  • Safe shutdown with data flushing

Memory Management

  • In-memory buffers for fast access

  • Periodic flushing to disk

  • Configurable buffer sizes (coming soon)

Visualization Options

  • Real-time plotting (coming soon)

  • Customizable plot layouts

  • Export to various formats