Skip to content

Logging Data

This guide explains how to use the Logger for data collection and variable tracking. Whether you're debugging your robot's behavior, collecting experimental data, or monitoring system performance, proper data logging is essential. All examples can be found in the logging_data.py script.

Variable Tracking

The Logger provides powerful variable tracking capabilities that let you monitor values over time. This is particularly useful for:

  • Recording sensor readings
  • Tracking control variables
  • Monitoring system state
  • Collecting experimental data

Here's how to set it up:

    logger = Logger(log_path="./logs", file_name="basic_variable_tracking")

    # Track a simple variable
    x = 42
    logger.track_variable(lambda: x, "x_value")

    # Track class attributes
    class Robot:
        def __init__(self):
            self.position = 0.0
            self.velocity = 0.0

    robot = Robot()
    logger.track_variable(lambda: robot.position, "position")
    logger.track_variable(lambda: robot.velocity, "velocity")

    # Update logged values
    logger.update()  # Records current values to buffer
    logger.info("Basic variables tracked and updated")

In this example:

  • track_variable() tells the logger to monitor a specific variable
  • The first argument is a function that returns the current value
  • The second argument is the variable name (used in CSV headers)
  • You can track multiple variables simultaneously
  • Variables are added to a buffer every time update() is called
  • The buffer is flushed based on the buffer_size parameter in the Logger constructor or manually with flush_buffer()
  • The buffer is automatically flushed when the Logger is destroyed
    # Update logged values
    logger.update()  # Records current values to buffer
    logger.info("Basic variables tracked and updated")

More Examples

1. Recording Sensor Data

This example demonstrates how to log data from a sensor in real-time. While this uses a simulated sensor, the pattern works for any sensor type:

class Sensor:
    """Example sensor class for demonstration."""

    def __init__(self):
        self.temperature = 20.0
        self.humidity = 0.5

    def update(self):
        """Simulate sensor updates."""
        self.temperature += 0.1
        self.humidity += 0.01

Key features demonstrated:

  • Continuous data collection
  • Real-time logging
  • Error handling for sensor failures
  • Proper resource cleanup

Example usage showing how to integrate this into your application:

    sensor = Sensor()
    logger = Logger(log_path="./logs", file_name="sensor_data")

    # Track sensor values
    logger.track_variable(lambda: sensor.temperature, "Temperature (C)")
    logger.track_variable(lambda: sensor.humidity, "Humidity (%)")

    # Simulate a few updates
    for _ in range(3):
        sensor.update()
        logger.update()
        time.sleep(0.1)

    logger.info("Sensor data logged")

2. Experiment Data Collection

A more complex example showing how to structure data collection for an experiment, including proper resource management and error handling.

class Experiment:
    """Example experiment class demonstrating data collection."""

    def __init__(self):
        self.logger = Logger(
            log_path="./experiments", file_name=f"trial_{time.strftime('%Y%m%d_%H%M%S')}", buffer_size=5000
        )

        self.input = 0.0
        self.output = 0.0
        self.error = 0.0
        self.steps = 0
        self.max_steps = 5  # For demonstration

        # Track experimental variables
        self.logger.track_variable(lambda: self.input, "Input")
        self.logger.track_variable(lambda: self.output, "Output")
        self.logger.track_variable(lambda: self.error, "Error")

    def is_complete(self):
        """Check if experiment is complete."""
        return self.steps >= self.max_steps

    def step(self):
        """Simulate one step of the experiment."""
        self.input += 0.1
        self.output = self.input * 2
        self.error = abs(self.output - self.input)
        self.steps += 1

    def run(self):
        """Run the experiment."""
        while not self.is_complete():
            self.step()
            self.logger.update()

Example usage:

    experiment = Experiment()
    experiment.run()
    print("Experiment completed and data saved")

Best Practices

  1. Variable Naming

    • Use clear, descriptive names for tracked variables
    • Follow a consistent naming convention
    • Consider adding units to variable names (e.g., "angle_deg", "velocity_mps")
  2. Update Frequency

    • Call update() at a consistent rate
    • Consider your data storage requirements
    • Balance logging frequency with system performance
  3. Resource Management

    • Always use proper cleanup procedures
    • Consider using context managers (with statements)
    • Handle interruptions gracefully
  4. Data Organization

    • Use meaningful file names
    • Structure your data logically
    • Include metadata when relevant

Working with Logged Data

Your logged data can be easily analyzed using common data analysis packages like pandas and matplotlib or used with other programs like Matlab.

Common Issues and Solutions

  1. High-Frequency Data

    • Increase buffer size for better performance
    • Consider logging only essential variables
    • Use appropriate data types
  2. Large Files

    • Split logs into manageable chunks
    • Clean up old logs regularly
    • Monitor disk space usage
  3. System Performance

    • Profile your logging impact
    • Adjust buffer sizes as needed
    • Balance logging frequency with requirements

If you have any questions or need further assistance, please post on the Open Source Leg community forum.