generated from wessel/boilerplate
feat(lifecycle & hw): added mqtt connection and installation setup
This commit is contained in:
@@ -41,3 +41,54 @@ You can configure specific database settings in the `docker-compose.yaml` in the
|
||||
ros2 launch g2_2025_grade_calculator_pkg grade_calculator.launch.xml
|
||||
```
|
||||
To change parameters when using the launch file it will need to be edited in the `src/g2_2025_grade_calculator_pkg/launch` folder. All parameters are already added to this document and thus only the values will need to be changed
|
||||
|
||||
|
||||
|
||||
### installation and setup for mqtt
|
||||
|
||||
```bash
|
||||
sudo apt install mosquitto
|
||||
|
||||
sudo apt-get install libpaho-mqtt-dev
|
||||
|
||||
|
||||
git clone https://github.com/eclipse/paho.mqtt.cpp
|
||||
cd paho.mqtt.cpp
|
||||
git co v1.5.4
|
||||
git submodule init
|
||||
git submodule update
|
||||
|
||||
cmake -Bbuild -H. -DPAHO_WITH_MQTT_C=ON -DPAHO_BUILD_EXAMPLES=ON
|
||||
sudo cmake --build build/ --target install
|
||||
```
|
||||
|
||||
## for launching lifecycle mqtt node
|
||||
|
||||
first:
|
||||
```bash
|
||||
ros2 run g2_2025_imu_reader_pkg g2_2025_lifecycle_node --ros-args -p comm_t:='mqtt'
|
||||
```
|
||||
|
||||
in other terminal:
|
||||
|
||||
```bash
|
||||
mosquitto -p 1884
|
||||
```
|
||||
|
||||
and in other terminal to inialize the subsecriber:
|
||||
```bash
|
||||
|
||||
ros2 lifecycle set /lifecycle_manager configure
|
||||
ros2 lifecycle set /lifecycle_manager activate
|
||||
|
||||
```
|
||||
|
||||
an finally publish a mesg to the sub in other terminal:
|
||||
|
||||
```bash
|
||||
mosquitto_pub -h localhost -p 1884 -t "esp32/imu" -m "nirvana"
|
||||
```
|
||||
close conn via:
|
||||
```bash
|
||||
ros2 lifecycle set /lifecycle_manager deactivate
|
||||
```
|
||||
|
||||
@@ -53,6 +53,13 @@ target_include_directories(g2_2025_lifecycle_node PRIVATE
|
||||
)
|
||||
ament_target_dependencies(g2_2025_lifecycle_node rclcpp rclcpp_lifecycle std_msgs sensor_msgs)
|
||||
|
||||
target_link_libraries(g2_2025_lifecycle_node
|
||||
paho-mqttpp3
|
||||
paho-mqtt3a
|
||||
)
|
||||
|
||||
|
||||
|
||||
install(
|
||||
TARGETS
|
||||
imu_database_writer
|
||||
@@ -60,6 +67,8 @@ install(
|
||||
DESTINATION lib/${PROJECT_NAME}
|
||||
)
|
||||
|
||||
set_target_properties(g2_2025_lifecycle_node PROPERTIES INSTALL_RPATH "/usr/local/lib")
|
||||
|
||||
if(BUILD_TESTING)
|
||||
find_package(ament_cmake_gtest REQUIRED)
|
||||
|
||||
|
||||
@@ -45,4 +45,61 @@ void HardwareInterface::close_device() {
|
||||
|
||||
}
|
||||
|
||||
} // namespace assignments::two::g2_2025_lifecycle_node
|
||||
class callback : public virtual mqtt::callback {
|
||||
public:
|
||||
void message_arrived(mqtt::const_message_ptr msg) override {
|
||||
// Use a named logger since this class isn't a rclcpp::Node
|
||||
RCLCPP_INFO(rclcpp::get_logger("hardware_interface"),
|
||||
"Message received: %s", msg->get_payload_str().c_str());
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
void HardwareInterface::mqtt_listener() {
|
||||
// Create persistent client and callback so they outlive this function.
|
||||
if (!mqtt_client) {
|
||||
mqtt_client = std::make_shared<mqtt::async_client>(SERVER_ADDRESS, CLIENT_ID);
|
||||
}
|
||||
if (!mqtt_cb) {
|
||||
mqtt_cb = std::make_shared<callback>();
|
||||
}
|
||||
|
||||
// attach callback (expects a reference)
|
||||
mqtt_client->set_callback(*mqtt_cb);
|
||||
|
||||
mqtt::connect_options connOpts;
|
||||
connOpts.set_keep_alive_interval(20);
|
||||
connOpts.set_clean_session(true);
|
||||
|
||||
try {
|
||||
mqtt_client->connect(connOpts)->wait();
|
||||
RCLCPP_INFO(this->get_logger(), "Connected to broker");
|
||||
|
||||
mqtt_client->subscribe(TOPIC, 1)->wait();
|
||||
RCLCPP_INFO(this->get_logger(), "Subscribed to topic: %s", TOPIC.c_str());
|
||||
// Note: do not disconnect here; keep client alive until close_mqtt_conn()
|
||||
} catch (const mqtt::exception& exc) {
|
||||
RCLCPP_ERROR(this->get_logger(), "Error: %s", exc.what());
|
||||
}
|
||||
}
|
||||
|
||||
void HardwareInterface::close_mqtt_conn() {
|
||||
try {
|
||||
if (mqtt_client) {
|
||||
if (mqtt_client->is_connected()) {
|
||||
mqtt_client->disconnect()->wait();
|
||||
RCLCPP_INFO(this->get_logger(), "Disconnected MQTT client");
|
||||
}
|
||||
// reset to allow destruction
|
||||
mqtt_client.reset();
|
||||
}
|
||||
if (mqtt_cb) {
|
||||
mqtt_cb.reset();
|
||||
}
|
||||
} catch (const mqtt::exception& exc) {
|
||||
RCLCPP_ERROR(this->get_logger(), "Error while disconnecting MQTT: %s", exc.what());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
} // namespace assignments::two::g2_2025_lifecycle_node
|
||||
|
||||
@@ -19,6 +19,11 @@
|
||||
#include <unistd.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include "config/serialib.h"
|
||||
#include <iostream>
|
||||
|
||||
|
||||
#include <mqtt/client.h>
|
||||
#include <mqtt/async_client.h>
|
||||
|
||||
#include "rclcpp/rclcpp.hpp"
|
||||
#include "rclcpp_lifecycle/lifecycle_node.hpp"
|
||||
@@ -30,12 +35,22 @@ class HardwareInterface : public rclcpp::Node {
|
||||
public:
|
||||
HardwareInterface();
|
||||
void read();
|
||||
void write(const std::string & data);
|
||||
bool open_device(const std::string & device_path, int baud_rate);
|
||||
void write(const std::string& data);
|
||||
bool open_device(const std::string& device_path, int baud_rate);
|
||||
bool is_device_open();
|
||||
void close_device();
|
||||
void mqtt_listener();
|
||||
void close_mqtt_conn();
|
||||
private:
|
||||
serialib serial;
|
||||
// MQTT defaults. Use static inline so they can be initialized in-class.
|
||||
static inline const std::string SERVER_ADDRESS = "tcp://localhost:1884";
|
||||
static inline const std::string CLIENT_ID = "cpp_mqtt_client";
|
||||
static inline const std::string TOPIC = "esp32/imu";
|
||||
|
||||
std::shared_ptr<mqtt::async_client> mqtt_client;
|
||||
std::shared_ptr<mqtt::callback> mqtt_cb;
|
||||
|
||||
|
||||
};
|
||||
} // namespace assignments::two::g2_2025_lifecycle_node
|
||||
|
||||
@@ -13,7 +13,7 @@ LifecycleManager::LifecycleManager() : rclcpp_lifecycle::LifecycleNode("lifecycl
|
||||
|
||||
device_path_ = this->declare_parameter<std::string>("device_path", "/dev/ttyUSB0");
|
||||
baudrate_ = this->declare_parameter<int>("baudrate", 115200);
|
||||
communication_type_ = this->declare_parameter<std::string>("communication_type", "serial"); // placeholder default serial or param mqtt
|
||||
communication_type_ = this->declare_parameter<std::string>("comm_t", "serial"); // placeholder default serial or param mqtt
|
||||
|
||||
// hardware interface instance
|
||||
hw_interface = std::make_shared<HardwareInterface>();
|
||||
@@ -39,11 +39,20 @@ void LifecycleManager::publish_imu_data(const std::string& data) { // placeholde
|
||||
rclcpp_lifecycle::node_interfaces::LifecycleNodeInterface::CallbackReturn
|
||||
LifecycleManager::on_configure(const rclcpp_lifecycle::State&) {
|
||||
|
||||
|
||||
RCLCPP_INFO(this->get_logger(), "configuring lifecycle...");
|
||||
|
||||
if (!hw_interface->open_device(device_path_, baudrate_)) {
|
||||
RCLCPP_ERROR(this->get_logger(), "Failed to open hardware device during configuration.");
|
||||
return rclcpp_lifecycle::node_interfaces::LifecycleNodeInterface::CallbackReturn::FAILURE;
|
||||
if (communication_type_ == "mqtt") {
|
||||
// RCLCPP_INFO(this->get_logger(), "Setting up MQTT communication...");
|
||||
// hw_interface->mqtt_listener();
|
||||
|
||||
} else {
|
||||
RCLCPP_INFO(this->get_logger(), "Using serial communication.");
|
||||
|
||||
if (!hw_interface->open_device(device_path_, baudrate_)) {
|
||||
RCLCPP_ERROR(this->get_logger(), "Failed to open hardware device during configuration.");
|
||||
return rclcpp_lifecycle::node_interfaces::LifecycleNodeInterface::CallbackReturn::FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
return rclcpp_lifecycle::node_interfaces::LifecycleNodeInterface::CallbackReturn::SUCCESS;
|
||||
@@ -53,9 +62,23 @@ rclcpp_lifecycle::node_interfaces::LifecycleNodeInterface::CallbackReturn
|
||||
LifecycleManager::on_activate(const rclcpp_lifecycle::State&) {
|
||||
|
||||
RCLCPP_INFO(this->get_logger(), "activating lifecycle...");
|
||||
if (!hw_interface->is_device_open()) {
|
||||
RCLCPP_ERROR(this->get_logger(), "Hardware device is not open during activation.");
|
||||
return rclcpp_lifecycle::node_interfaces::LifecycleNodeInterface::CallbackReturn::FAILURE;
|
||||
|
||||
if (communication_type_ == "mqtt") {
|
||||
RCLCPP_INFO(this->get_logger(), "Setting up MQTT communication...");
|
||||
hw_interface->mqtt_listener();
|
||||
return rclcpp_lifecycle::node_interfaces::LifecycleNodeInterface::CallbackReturn::SUCCESS;
|
||||
|
||||
} else {
|
||||
RCLCPP_INFO(this->get_logger(), "Using serial communication.");
|
||||
if (!hw_interface->is_device_open()) {
|
||||
RCLCPP_ERROR(this->get_logger(), "Hardware device is not open during activation.");
|
||||
return rclcpp_lifecycle::node_interfaces::LifecycleNodeInterface::CallbackReturn::FAILURE;
|
||||
}
|
||||
if (!hw_interface->open_device(device_path_, baudrate_)) {
|
||||
|
||||
RCLCPP_ERROR(this->get_logger(), "Failed to open hardware device during configuration.");
|
||||
return rclcpp_lifecycle::node_interfaces::LifecycleNodeInterface::CallbackReturn::FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
RCLCPP_INFO(this->get_logger(), "Hardware device is open, starting data read...");
|
||||
@@ -71,7 +94,13 @@ LifecycleManager::on_deactivate(const rclcpp_lifecycle::State&) {
|
||||
|
||||
RCLCPP_INFO(this->get_logger(), "deactivating lifecycle...");
|
||||
|
||||
hw_interface->close_device();
|
||||
if (communication_type_ == "mqtt")
|
||||
{
|
||||
hw_interface->close_mqtt_conn();
|
||||
} else {
|
||||
hw_interface->close_device();
|
||||
}
|
||||
|
||||
|
||||
return rclcpp_lifecycle::node_interfaces::LifecycleNodeInterface::CallbackReturn::SUCCESS;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user