generated from wessel/boilerplate
docs: Update lifecycle node documentation
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -31,6 +31,7 @@ qtcreator-*
|
||||
|
||||
# Colcon custom files
|
||||
COLCON_IGNORE
|
||||
!src/*/COLCON_IGNORE
|
||||
AMENT_IGNORE
|
||||
|
||||
.vscode
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# HardwareInterface (`assignments::two::g2_2025_lifecycle_node`)
|
||||
|
||||
## Overview
|
||||
The `HardwareInterface` is a ROS2 node responsible for managing low-level hardware communication with IMU sensors. It abstracts the complexity of dual communication backends (serial and MQTT), provides JSON parsing of sensor data, and publishes standardized `sensor_msgs::msg::Imu` messages to the ROS2 ecosystem. The node handles continuous data acquisition, buffering of fragmented reads, and robust error recovery.
|
||||
The `HardwareInterface` is a c++ class responsible for managing low-level hardware communication with ESP32-IMU combination via serial/MQTT and provides JSON parsing of sensor data, and publishes standardized `sensor_msgs::msg::Imu` messages to the database writer.
|
||||
|
||||
#### Implementation Details
|
||||
|
||||
@@ -46,8 +46,6 @@ HardwareInterface()
|
||||
- **`CLIENT_ID`**: `"cpp_mqtt_client"` — MQTT client identifier
|
||||
- **`TOPIC`**: `"esp32/imu"` — Default subscription topic for IMU data
|
||||
|
||||
---
|
||||
|
||||
## Core Functions
|
||||
|
||||
### `void start_read()`
|
||||
@@ -71,8 +69,6 @@ Initiates continuous serial data acquisition in a background thread.
|
||||
**Error Handling:**
|
||||
- Invalid JSON lines are logged as errors in `parse_data()` but do not crash the thread
|
||||
|
||||
---
|
||||
|
||||
### `void stop_read()`
|
||||
|
||||
Cleanly terminates the background reader thread.
|
||||
@@ -87,8 +83,6 @@ Cleanly terminates the background reader thread.
|
||||
- Uses atomic flag for lock-free signaling
|
||||
- Blocks until thread joins, guaranteeing clean shutdown
|
||||
|
||||
---
|
||||
|
||||
### `void parse_data(const std::string& data)`
|
||||
|
||||
Deserializes a JSON string into a ROS2 IMU message and publishes it.
|
||||
@@ -115,8 +109,6 @@ Deserializes a JSON string into a ROS2 IMU message and publishes it.
|
||||
- Catches `nlohmann::json::exception` and logs parsing errors without crashing
|
||||
- Handles missing fields gracefully using `.value()` with default 0.0
|
||||
|
||||
---
|
||||
|
||||
### `void publish_imu_data(const sensor_msgs::msg::Imu::SharedPtr msg)`
|
||||
|
||||
Publishes an IMU message to the ROS2 topic.
|
||||
@@ -125,8 +117,6 @@ Publishes an IMU message to the ROS2 topic.
|
||||
- Dereferences the shared pointer and publishes to `imu_publisher`
|
||||
- Operation is thread-safe (rclcpp publishers support multi-threaded access)
|
||||
|
||||
---
|
||||
|
||||
### `void mqtt_configure()`
|
||||
|
||||
Sets up the MQTT infrastructure for broker communication.
|
||||
@@ -140,8 +130,6 @@ Sets up the MQTT infrastructure for broker communication.
|
||||
- Client and callback objects must outlive this function to maintain the connection
|
||||
- Using `shared_ptr` ensures proper lifetime management
|
||||
|
||||
---
|
||||
|
||||
### `void mqtt_reader()`
|
||||
|
||||
Attaches callbacks to the MQTT client to begin receiving messages.
|
||||
@@ -151,8 +139,6 @@ Attaches callbacks to the MQTT client to begin receiving messages.
|
||||
- Logs that the listener has started
|
||||
- Returns; the async client handles message reception in background threads
|
||||
|
||||
---
|
||||
|
||||
### `void mqtt_connect()`
|
||||
|
||||
Establishes connection to the MQTT broker and subscribes to the sensor topic.
|
||||
@@ -168,8 +154,6 @@ Establishes connection to the MQTT broker and subscribes to the sensor topic.
|
||||
**Error Handling:**
|
||||
- Catches `mqtt::exception` and logs errors; does not throw or crash
|
||||
|
||||
---
|
||||
|
||||
### `void close_mqtt_conn()`
|
||||
|
||||
Cleanly disconnects from the MQTT broker and cleans up resources.
|
||||
@@ -184,8 +168,6 @@ Cleanly disconnects from the MQTT broker and cleans up resources.
|
||||
- Catches `mqtt::exception` and logs errors
|
||||
- Continues cleanup even if errors occur
|
||||
|
||||
---
|
||||
|
||||
### `bool open_device(const std::string& device_path, int baud_rate)`
|
||||
|
||||
Opens and configures a serial port device.
|
||||
@@ -203,8 +185,6 @@ Opens and configures a serial port device.
|
||||
- Checks if the returned value is 1 (success)
|
||||
- Logs success or error status
|
||||
|
||||
---
|
||||
|
||||
### `bool is_device_open()`
|
||||
|
||||
Queries the current state of the serial device.
|
||||
@@ -213,8 +193,6 @@ Queries the current state of the serial device.
|
||||
- `true` if the device is open
|
||||
- `false` otherwise
|
||||
|
||||
---
|
||||
|
||||
### `void close_device()`
|
||||
|
||||
Closes the serial port and releases resources.
|
||||
@@ -223,8 +201,6 @@ Closes the serial port and releases resources.
|
||||
- Calls `serial.closeDevice()`
|
||||
- Ensures the device is no longer accessible for reads/writes
|
||||
|
||||
---
|
||||
|
||||
### `void write(const std::string& data)`
|
||||
|
||||
Writes data to the serial device.
|
||||
@@ -233,8 +209,6 @@ Writes data to the serial device.
|
||||
- Logs the write operation
|
||||
- Calls `serial.writeString()` with the data
|
||||
|
||||
---
|
||||
|
||||
## MQTT Callback Handler
|
||||
|
||||
### `class callback : public virtual mqtt::callback`
|
||||
@@ -246,7 +220,6 @@ A nested class that implements the Paho MQTT callback interface.
|
||||
- Invoked when a message arrives on a subscribed topic
|
||||
- Extracts the payload string via `msg->get_payload_str()`
|
||||
- Calls `parse_data()` to deserialize and publish the IMU message
|
||||
---
|
||||
|
||||
## Data Flow Architecture
|
||||
|
||||
@@ -294,8 +267,6 @@ JSON Parse → sensor_msgs::msg::Imu
|
||||
publish_imu_data() → ROS Topic `imu_data`
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Buffer Management & Message Reconstruction
|
||||
|
||||
The `partial_buffer_` member implements a robust strategy for handling fragmented serial reads:
|
||||
@@ -312,8 +283,6 @@ The `partial_buffer_` member implements a robust strategy for handling fragmente
|
||||
- Multiple messages can arrive in a single read
|
||||
- Buffering ensures robust handling of all edge cases
|
||||
|
||||
---
|
||||
|
||||
## Error Handling & Recovery
|
||||
|
||||
| Scenario | Behavior | Recovery |
|
||||
@@ -325,8 +294,6 @@ The `partial_buffer_` member implements a robust strategy for handling fragmente
|
||||
| MQTT broker unreachable | Exception caught and logged | Retry via `mqtt_connect()` |
|
||||
| MQTT message error | Exception caught and logged | Connection remains for next message |
|
||||
|
||||
---
|
||||
|
||||
## Thread Safety
|
||||
|
||||
- **Atomic Flag**: `reading_` uses `std::atomic_bool` for lock-free thread signaling
|
||||
@@ -390,8 +357,6 @@ ros2 lifecycle set /lifecycle_manager deactivate
|
||||
ros2 lifecycle set /lifecycle_manager shutdown
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Design Patterns
|
||||
|
||||
1. **Abstraction Pattern**: Encapsulates serial and MQTT complexity behind a unified interface
|
||||
@@ -400,9 +365,6 @@ ros2 lifecycle set /lifecycle_manager shutdown
|
||||
4. **Dual Backend Strategy**: Runtime selection of communication mode (serial or MQTT)
|
||||
5. **JSON Deserialization**: Uses industry-standard `nlohmann::json` for robust parsing
|
||||
|
||||
---
|
||||
|
||||
|
||||
## Dependencies
|
||||
|
||||
- **rclcpp**: ROS2 C++ client library
|
||||
@@ -410,43 +372,3 @@ ros2 lifecycle set /lifecycle_manager shutdown
|
||||
- **paho-mqtt**: Paho C/C++ MQTT client library
|
||||
- **nlohmann/json**: Header-only JSON parsing library
|
||||
- **serialib**: Custom serial communication wrapper
|
||||
|
||||
---
|
||||
|
||||
## Class Diagram
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────┐
|
||||
│ HardwareInterface │
|
||||
│ (rclcpp::Node) │
|
||||
├─────────────────────────────────────┤
|
||||
│ Private Members: │
|
||||
│ - serialib serial │
|
||||
│ - async_client mqtt_client │
|
||||
│ - callback mqtt_cb │
|
||||
│ - thread read_thread_ │
|
||||
│ - atomic_bool reading_ │
|
||||
│ - string partial_buffer_ │
|
||||
│ - Publisher imu_publisher │
|
||||
├─────────────────────────────────────┤
|
||||
│ Public Methods: │
|
||||
│ + start_read() │
|
||||
│ + stop_read() │
|
||||
│ + open_device() │
|
||||
│ + close_device() │
|
||||
│ + is_device_open() │
|
||||
│ + write() │
|
||||
│ + mqtt_configure() │
|
||||
│ + mqtt_reader() │
|
||||
│ + mqtt_connect() │
|
||||
│ + close_mqtt_conn() │
|
||||
│ + parse_data() │
|
||||
│ + publish_imu_data() │
|
||||
└─────────────────────────────────────┘
|
||||
↑
|
||||
│ orchestrated by
|
||||
│
|
||||
┌──────────────────┐
|
||||
│ LifecycleManager │
|
||||
└──────────────────┘
|
||||
```
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# 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.
|
||||
The `LifecycleManager` is the lifecycle node responsible for receiving the data of the ESP32-IMU combination via serial/MQTT and publishing that data to the database management node. For the functionality outside of the lifecycle see [HardwareInterface.md](HardwareInterface.md])
|
||||
|
||||
#### Implementation Details
|
||||
|
||||
@@ -9,7 +9,7 @@ The `LifecycleManager` is the core lifecycle-aware node responsible for managing
|
||||
|
||||
- **`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.
|
||||
- **`comm_t`** (string, default: "serial"): Communication type selector—either "serial" or "mqtt".
|
||||
|
||||
**Constructor**
|
||||
```cpp
|
||||
@@ -63,18 +63,15 @@ LifecycleManager()
|
||||
|
||||
## Communication Architecture
|
||||
|
||||
### Dual Backend Support
|
||||
The `LifecycleManager` switches communication type depending on the `comm_t` parameter:
|
||||
|
||||
The `LifecycleManager` provides a flexible, pluggable communication architecture via the `comm_t` parameter:
|
||||
|
||||
#### Serial Communication Path
|
||||
#### Serial Communication
|
||||
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
|
||||
- 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`
|
||||
|
||||
@@ -83,7 +80,7 @@ The `LifecycleManager` provides a flexible, pluggable communication architecture
|
||||
- Joins the thread to ensure clean termination
|
||||
- Closes the serial device
|
||||
|
||||
#### MQTT Communication Path
|
||||
#### MQTT Communication
|
||||
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
|
||||
@@ -97,8 +94,6 @@ The `LifecycleManager` provides a flexible, pluggable communication architecture
|
||||
- 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:
|
||||
@@ -120,8 +115,6 @@ ros2 lifecycle set /lifecycle_manager deactivate
|
||||
ros2 lifecycle set /lifecycle_manager shutdown
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Data Flow
|
||||
|
||||
### Serial Data Flow
|
||||
@@ -156,16 +149,12 @@ 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
|
||||
@@ -173,8 +162,6 @@ imu_publisher → ROS2 Topic (`imu_data`)
|
||||
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:
|
||||
@@ -191,8 +178,6 @@ The `LifecycleManager` delegates all hardware operations to the `HardwareInterfa
|
||||
| Parse JSON payload | `parse_data(json_string)` | on_activate (continuous) |
|
||||
| Publish IMU message | `publish_imu_data(imu_msg)` | on_activate (continuous) |
|
||||
|
||||
---
|
||||
|
||||
## Usage Example
|
||||
|
||||
```bash
|
||||
|
||||
@@ -38,18 +38,17 @@ You can configure specific database settings in the `docker-compose.yaml` in the
|
||||
|
||||
### Start the IMU Reader program
|
||||
```bash
|
||||
ros2 launch g2_2025_imu_reader_pkg imu_reader.launch.xml
|
||||
For Serial:
|
||||
ros2 launch g2_2025_imu_reader_pkg serial.launch.xml
|
||||
|
||||
For MQTT:
|
||||
ros2 launch g2_2025_imu_reader_pkg mqtt.launch.xml
|
||||
```
|
||||
To change parameters when using the launch file it will need to be edited in the `src/g2_2025_imu_reader_pkg/launch` folder. All parameters are already added to this document and thus only the values will need to be changed
|
||||
|
||||
## For launching lifecycle mqtt node
|
||||
### Use the Lifecycle Node
|
||||
|
||||
First:
|
||||
```bash
|
||||
ros2 run g2_2025_imu_reader_pkg g2_2025_lifecycle_node --ros-args -p comm_t:='mqtt'
|
||||
```
|
||||
|
||||
and in other terminal to inialize the subscriber:
|
||||
To setup the lifecycle node the following commands can be used. They must be used in this order.
|
||||
```bash
|
||||
ros2 lifecycle set /lifecycle_manager configure
|
||||
ros2 lifecycle set /lifecycle_manager activate
|
||||
|
||||
Reference in New Issue
Block a user