Files
ros2-assignments/doc/architecture/nodes/LifecycleManager.md
2025-11-06 19:48:57 +01:00

8.4 KiB

LifecycleManager (assignments::two::g2_2025_lifecycle_node)

Overview

The LifecycleManager is the core lifecycle-aware node responsible for managing the IMU reader system's operational states and hardware communication. It orchestrates transitions between configuration, activation, and deactivation phases, abstracting the complexity of dual communication backends (serial and MQTT) into a unified interface.

Implementation Details

Parameters

  • device_path (string, default: "/dev/ttyUSB0"): Serial device path for hardware connection (e.g., USB serial adapter).
  • baudrate (int, default: 115200): Serial communication baud rate in bits per second.
  • comm_t (string, default: "serial"): Communication type selector—either "serial" or "mqtt" to determine which backend to use.

Constructor

LifecycleManager()
  • Initializes ROS2 lifecycle node with name lifecycle_manager
  • Declares and reads configuration parameters: device_path, baudrate, and comm_t
  • Creates a shared instance of HardwareInterface for managing all hardware operations
  • Logs initialization status and readiness

Core Functions

CallbackReturn on_configure(const State&)

  • Enters the UnconfiguredInactive transition
  • Checks the comm_t parameter to route initialization:
    • MQTT mode: Calls hw_interface->mqtt_configure() to set up the MQTT client and broker connection
    • Serial mode: Calls hw_interface->open_device(device_path_, baudrate_) to open and configure the serial port
  • Returns SUCCESS if device initialization succeeds, FAILURE if serial/MQTT setup fails
  • Logs configuration status and any errors
  • Example test code (currently commented) demonstrates direct JSON parsing for validation

CallbackReturn on_activate(const State&)

  • Enters the InactiveActive transition
  • Checks the comm_t parameter to start the appropriate reader:
    • MQTT mode: Calls hw_interface->mqtt_reader() to attach MQTT callbacks and begin receiving messages
    • Serial mode: Calls hw_interface->start_read() to spawn a background thread that continuously reads from the serial device
  • Returns SUCCESS after reader startup
  • Logs activation status and selected communication type

CallbackReturn on_deactivate(const State&)

  • Enters the ActiveInactive transition
  • Checks the comm_t parameter to cleanly stop operations:
    • MQTT mode: Calls hw_interface->close_mqtt_conn() to disconnect from the broker and clean up resources
    • Serial mode:
      • Verifies device state with hw_interface->is_device_open()
      • Calls hw_interface->stop_read() to signal the reader thread to exit and joins it
      • Calls hw_interface->close_device() to release the serial port
  • Returns SUCCESS after cleanup completes
  • Logs deactivation and resource release

CallbackReturn on_shutdown(const State&)

  • Enters the InactiveFinalized transition
  • Performs final shutdown logging
  • Returns SUCCESS

CallbackReturn on_cleanup(const State&)

  • Called during error recovery or explicit cleanup commands
  • Performs resource cleanup and state logging
  • Returns SUCCESS

Communication Architecture

Dual Backend Support

The LifecycleManager provides a flexible, pluggable communication architecture via the comm_t parameter:

Serial Communication Path

  1. Configuration Phase (on_configure):

    • Opens the serial device at the path specified by device_path and baudrate
    • Validates device readiness
  2. Activation Phase (on_activate):

    • Spawns a background reader thread via hw_interface->start_read()
    • Thread continuously polls the serial device with a timeout
    • Reads are accumulated in a partial buffer, split on newline, and parsed as JSON
    • Each valid JSON IMU payload is parsed into a sensor_msgs::msg::Imu and published to the ROS topic imu/data
  3. Deactivation Phase (on_deactivate):

    • Signals the reader thread to stop via atomic flag
    • Joins the thread to ensure clean termination
    • Closes the serial device

MQTT Communication Path

  1. Configuration Phase (on_configure):

    • Creates a persistent MQTT async client pointing to the broker at SERVER_ADDRESS (default: tcp://localhost:1883)
    • Initializes MQTT callback infrastructure
  2. Activation Phase (on_activate):

    • Attaches MQTT callbacks to the client
    • Subscribes to the topic specified by TOPIC (default: esp32/imu)
    • The async client runs background threads to receive messages
  3. Deactivation Phase (on_deactivate):

    • Disconnects from the broker
    • Cleans up MQTT client and callback resources

Lifecycle Commands

To interact with the LifecycleManager from the command line, use the following ROS2 lifecycle service calls:

# List current lifecycle state
ros2 lifecycle list /LifecycleManager

# Transition: UNCONFIGURED -> INACTIVE
ros2 lifecycle set /LifecycleManager configure

# Transition: INACTIVE -> UNCONFIGURED
ros2 lifecycle set /LifecycleManager cleanup

# Transition: INACTIVE -> ACTIVE
ros2 lifecycle set /LifecycleManager activate

# Transition: ACTIVE -> INACTIVE
ros2 lifecycle set /LifecycleManager deactivate

# Transition: INACTIVE -> FINALIZED
ros2 lifecycle set /LifecycleManager shutdown

img

Data Flow

Serial Data Flow

Hardware Device
      ↓
Serial Port (/dev/ttyUSB0)
      ↓
Background Reader Thread (start_read)
      ↓
Partial Buffer Accumulation
      ↓
JSON Line Extraction & Sanitization
      ↓
parse_data() ← Deserializes JSON to sensor_msgs::msg::Imu
      ↓
imu_publisher → ROS2 Topic (`imu_data`)

MQTT Data Flow

MQTT Broker (localhost:1883)
      ↓
MQTT Async Client (Background Thread)
      ↓
Subscription to Topic (esp32/imu)
      ↓
MQTT Callback Handler
      ↓
parse_data() ← Deserializes JSON to sensor_msgs::msg::Imu
      ↓
imu_publisher → ROS2 Topic (`imu_data`)

Error Handling

  • Serial Device Failures: If open_device() fails during configuration, on_configure() returns FAILURE and the system remains in the UNCONFIGURED state
  • Communication Errors: JSON parse errors from invalid payloads are caught and logged without crashing the node; the reader continues listening for the next message
  • Thread Safety: The reader thread uses an atomic flag (reading_) for clean stop signaling and ensures all resources are properly joined before returning from on_deactivate()

Design Patterns

  1. Strategy Pattern: The comm_t parameter enables runtime selection of communication backend without changing node code
  2. Lifecycle Pattern: Follows ROS2 managed node pattern for predictable initialization, startup, and shutdown sequences
  3. Thread Safety: Atomic flags and resource cleanup ensure the reader thread can be safely started and stopped
  4. Buffer Accumulation: Partial message buffering handles fragmented serial reads and ensures complete JSON objects are parsed

Integration with HardwareInterface

The LifecycleManager delegates all hardware operations to the HardwareInterface class:

Operation Method Lifecycle Phase
Open serial device open_device(path, baud) on_configure
Start reading start_read() on_activate
Stop reading stop_read() on_deactivate
Close serial device close_device() on_deactivate
Configure MQTT mqtt_configure() on_configure
Start MQTT reading mqtt_reader() on_activate
Close MQTT connection close_mqtt_conn() on_deactivate
Parse JSON payload parse_data(json_string) on_activate (continuous)
Publish IMU message publish_imu_data(imu_msg) on_activate (continuous)

Usage Example

# Launch the node with serial communication at /dev/ttyUSB0, 115200 baud
ros2 run g2_2025_imu_reader_pkg g2_2025_lifecycle_node \
  --ros-args \
  -p device_path:=/dev/ttyUSB0 \
  -p baudrate:=115200 \
  -p comm_t:=serial

# Alternatively, launch with MQTT communication
ros2 run g2_2025_imu_reader_pkg g2_2025_lifecycle_node \
  --ros-args \
  -p comm_t:=mqtt

# In another terminal, configure and activate the lifecycle
ros2 lifecycle set /LifecycleManager configure
ros2 lifecycle set /LifecycleManager activate

# Subscribe to published IMU data
ros2 topic echo /imu_data

# Deactivate and shutdown
ros2 lifecycle set /LifecycleManager deactivate
ros2 lifecycle set /LifecycleManager shutdown