feat(lifecycle & hw): added serial lib and serial comunication functions with params.

This commit is contained in:
2025-10-29 18:29:10 +01:00
committed by Vincent Winter
parent 8696eee197
commit bd8400027f
8 changed files with 1667 additions and 5 deletions

View File

@@ -40,4 +40,59 @@ You can configure specific database settings in the `docker-compose.yaml` in the
```bash
ros2 launch g2_2025_imu_reader_pkg imu_reader.launch.xml
```
<<<<<<< HEAD
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
=======
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
```
>>>>>>> 8b04168 (feat(lifecycle & hw): added mqtt connection and installation setup)

View File

@@ -59,9 +59,16 @@ ament_target_dependencies(g2_2025_lifecycle_node rclcpp rclcpp_lifecycle std_msg
target_link_libraries(g2_2025_lifecycle_node
paho-mqttpp3
paho-mqtt3a
<<<<<<< HEAD
nlohmann_json::nlohmann_json
)
=======
)
>>>>>>> 8b04168 (feat(lifecycle & hw): added mqtt connection and installation setup)
install(
TARGETS
g2_2025_imu_database_writer_node

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,270 @@
/*!
\file serialib.h
\brief Header file of the class serialib. This class is used for communication over a serial device.
\author Philippe Lucidarme (University of Angers)
\version 2.0
\date december the 27th of 2019
This Serial library is used to communicate through serial port.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE X CONSORTIUM BE LIABLE FOR ANY CLAIM,
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
This is a licence-free software, it can be used by anyone who try to build a better world.
*/
#ifndef SERIALIB_H
#define SERIALIB_H
#if defined(__CYGWIN__)
// This is Cygwin special case
#include <sys/time.h>
#endif
// Include for windows
#if defined (_WIN32) || defined (_WIN64)
#if defined(__GNUC__)
// This is MinGW special case
#include <sys/time.h>
#else
// sys/time.h does not exist on "actual" Windows
#define NO_POSIX_TIME
#endif
// Accessing to the serial port under Windows
#include <windows.h>
#endif
// Include for Linux
#if defined (__linux__) || defined(__APPLE__)
#include <stdlib.h>
#include <sys/types.h>
#include <sys/shm.h>
#include <termios.h>
#include <string.h>
#include <iostream>
#include <sys/time.h>
// File control definitions
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>
#endif
/*! To avoid unused parameters */
#define UNUSED(x) (void)(x)
/**
* number of serial data bits
*/
enum SerialDataBits {
SERIAL_DATABITS_5, /**< 5 databits */
SERIAL_DATABITS_6, /**< 6 databits */
SERIAL_DATABITS_7, /**< 7 databits */
SERIAL_DATABITS_8, /**< 8 databits */
SERIAL_DATABITS_16, /**< 16 databits */
};
/**
* number of serial stop bits
*/
enum SerialStopBits {
SERIAL_STOPBITS_1, /**< 1 stop bit */
SERIAL_STOPBITS_1_5, /**< 1.5 stop bits */
SERIAL_STOPBITS_2, /**< 2 stop bits */
};
/**
* type of serial parity bits
*/
enum SerialParity {
SERIAL_PARITY_NONE, /**< no parity bit */
SERIAL_PARITY_EVEN, /**< even parity bit */
SERIAL_PARITY_ODD, /**< odd parity bit */
SERIAL_PARITY_MARK, /**< mark parity */
SERIAL_PARITY_SPACE /**< space bit */
};
/*! \class serialib
\brief This class is used for communication over a serial device.
*/
class serialib
{
public:
//_____________________________________
// ::: Constructors and destructors :::
// Constructor of the class
serialib ();
// Destructor
~serialib ();
//_________________________________________
// ::: Configuration and initialization :::
// Open a device
char openDevice(const char *Device, const unsigned int Bauds,
SerialDataBits Databits = SERIAL_DATABITS_8,
SerialParity Parity = SERIAL_PARITY_NONE,
SerialStopBits Stopbits = SERIAL_STOPBITS_1);
// Check device opening state
bool isDeviceOpen();
// Close the current device
void closeDevice();
//___________________________________________
// ::: Read/Write operation on characters :::
// Write a char
int writeChar (char);
// Read a char (with timeout)
int readChar (char *pByte,const unsigned int timeOut_ms=0);
//________________________________________
// ::: Read/Write operation on strings :::
// Write a string
int writeString (const char *String);
// Read a string (with timeout)
int readString ( char *receivedString,
char finalChar,
unsigned int maxNbBytes,
const unsigned int timeOut_ms=0);
// _____________________________________
// ::: Read/Write operation on bytes :::
// Write an array of bytes
int writeBytes(const void *Buffer, const unsigned int NbBytes, unsigned int *NbBytesWritten);
int writeBytes (const void *Buffer, const unsigned int NbBytes);
// Read an array of byte (with timeout)
int readBytes (void *buffer,unsigned int maxNbBytes,const unsigned int timeOut_ms=0, unsigned int sleepDuration_us=100);
// _________________________
// ::: Special operation :::
// Empty the received buffer
char flushReceiver();
// Return the number of bytes in the received buffer
int available();
// _________________________
// ::: Access to IO bits :::
// Set CTR status (Data Terminal Ready, pin 4)
bool DTR(bool status);
bool setDTR();
bool clearDTR();
// Set RTS status (Request To Send, pin 7)
bool RTS(bool status);
bool setRTS();
bool clearRTS();
// Get RI status (Ring Indicator, pin 9)
bool isRI();
// Get DCD status (Data Carrier Detect, pin 1)
bool isDCD();
// Get CTS status (Clear To Send, pin 8)
bool isCTS();
// Get DSR status (Data Set Ready, pin 9)
bool isDSR();
// Get RTS status (Request To Send, pin 7)
bool isRTS();
// Get CTR status (Data Terminal Ready, pin 4)
bool isDTR();
private:
// Read a string (no timeout)
int readStringNoTimeOut (char *String,char FinalChar,unsigned int MaxNbBytes);
// Current DTR and RTS state (can't be read on WIndows)
bool currentStateRTS;
bool currentStateDTR;
#if defined (_WIN32) || defined( _WIN64)
// Handle on serial device
HANDLE hSerial;
// For setting serial port timeouts
COMMTIMEOUTS timeouts;
#endif
#if defined (__linux__) || defined(__APPLE__)
int fd;
#endif
};
/*! \class timeOut
\brief This class can manage a timer which is used as a timeout.
*/
// Class timeOut
class timeOut
{
public:
// Constructor
timeOut();
// Init the timer
void initTimer();
// Return the elapsed time since initialization
unsigned long int elapsedTime_ms();
private:
#if defined (NO_POSIX_TIME)
// Used to store the previous time (for computing timeout)
LONGLONG counterFrequency;
LONGLONG previousTime;
#else
// Used to store the previous time (for computing timeout)
struct timeval previousTime;
#endif
};
#endif // serialib_H

View File

@@ -7,8 +7,99 @@ HardwareInterface::HardwareInterface() : Node("hardware_interface") {
}
void HardwareInterface::some_hardware_method() {
void HardwareInterface::read() {
char buffer[100];
RCLCPP_INFO(this->get_logger(), "Interacting with hardware...");
serial.readString(buffer, '\n', 14, 2000); // or readBytes depending on the data format ;)
RCLCPP_INFO(this->get_logger(), "Data read from hardware: %s", buffer);
}
void HardwareInterface::write(const std::string& data) {
RCLCPP_INFO(this->get_logger(), "Writing to hardware...");
serial.writeString(data.c_str());
}
bool HardwareInterface::open_device(const std::string& device_path, int baud_rate) {
char errorOpening = serial.openDevice(device_path.c_str(), baud_rate);
if (errorOpening != 1) {
RCLCPP_ERROR(this->get_logger(), "Error opening serial port: %d", errorOpening);
return false;
}
RCLCPP_INFO(this->get_logger(), "Serial port opened successfully.");
return true;
}
bool HardwareInterface::is_device_open() {
return serial.isDeviceOpen();
}
void HardwareInterface::close_device() {
serial.closeDevice();
}
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

View File

@@ -14,6 +14,16 @@
#include <random>
#include <vector>
#include <chrono>
#include <termios.h>
#include <fcntl.h>
#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"
@@ -24,8 +34,23 @@ 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);
bool is_device_open();
void close_device();
void mqtt_listener();
void close_mqtt_conn();
private:
void some_hardware_method();
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

View File

@@ -1,4 +1,5 @@
#include "lifecycle_manager.hpp"
#include "hardware_interface.hpp"
namespace assignments::two::g2_2025_lifecycle_node {
@@ -10,6 +11,12 @@ LifecycleManager::LifecycleManager() : rclcpp_lifecycle::LifecycleNode("lifecycl
imu_publisher = this->create_publisher<std_msgs::msg::String>("imu_data", 10);
RCLCPP_INFO(this->get_logger(), "IMU Publisher has been created");
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>("comm_t", "serial"); // placeholder default serial or param mqtt
// hardware interface instance
hw_interface = std::make_shared<HardwareInterface>();
}
@@ -31,25 +38,84 @@ void LifecycleManager::publish_imu_data(const std::string & data) { // placehold
rclcpp_lifecycle::node_interfaces::LifecycleNodeInterface::CallbackReturn
LifecycleManager::on_configure(const rclcpp_lifecycle::State&) {
RCLCPP_INFO(this->get_logger(), "configuring lifecycle...");
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;
}
rclcpp_lifecycle::node_interfaces::LifecycleNodeInterface::CallbackReturn
LifecycleManager::on_activate(const rclcpp_lifecycle::State&) {
RCLCPP_INFO(this->get_logger(), "activating lifecycle...");
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...");
hw_interface->read();
return rclcpp_lifecycle::node_interfaces::LifecycleNodeInterface::CallbackReturn::SUCCESS;
}
rclcpp_lifecycle::node_interfaces::LifecycleNodeInterface::CallbackReturn
LifecycleManager::on_deactivate(const rclcpp_lifecycle::State&) {
RCLCPP_INFO(this->get_logger(), "deactivating lifecycle...");
if (communication_type_ == "mqtt")
{
hw_interface->close_mqtt_conn();
} else {
hw_interface->close_device();
}
return rclcpp_lifecycle::node_interfaces::LifecycleNodeInterface::CallbackReturn::SUCCESS;
}
rclcpp_lifecycle::node_interfaces::LifecycleNodeInterface::CallbackReturn
LifecycleManager::on_shutdown(const rclcpp_lifecycle::State&) {
RCLCPP_INFO(this->get_logger(), "shutting down lifecycle...");
return rclcpp_lifecycle::node_interfaces::LifecycleNodeInterface::CallbackReturn::SUCCESS;
}
rclcpp_lifecycle::node_interfaces::LifecycleNodeInterface::CallbackReturn
LifecycleManager::on_cleanup(const rclcpp_lifecycle::State&) {
RCLCPP_INFO(this->get_logger(), "cleaning up lifecycle...");
return rclcpp_lifecycle::node_interfaces::LifecycleNodeInterface::CallbackReturn::SUCCESS;
}
} // namespace assignments::two::g2_2025_lifecycle_node

View File

@@ -18,6 +18,7 @@
#include "rclcpp/rclcpp.hpp"
#include "rclcpp_lifecycle/lifecycle_node.hpp"
#include "std_msgs/msg/string.hpp"
#include "hardware_interface.hpp"
namespace assignments::two::g2_2025_lifecycle_node {
@@ -26,11 +27,21 @@ public:
LifecycleManager();
private:
rclcpp::Publisher<std_msgs::msg::String>::SharedPtr imu_publisher;
void publish_imu_data(const std::string & data);
std::string device_path_;
int baudrate_;
std::string communication_type_;
// Hardware interface to interact with the IMU device.
std::shared_ptr<HardwareInterface> hw_interface;
void publish_imu_data(const std::string & data);
rclcpp_lifecycle::node_interfaces::LifecycleNodeInterface::CallbackReturn on_configure(const rclcpp_lifecycle::State&);
rclcpp_lifecycle::node_interfaces::LifecycleNodeInterface::CallbackReturn on_activate(const rclcpp_lifecycle::State&);
rclcpp_lifecycle::node_interfaces::LifecycleNodeInterface::CallbackReturn on_deactivate(const rclcpp_lifecycle::State&);
rclcpp_lifecycle::node_interfaces::LifecycleNodeInterface::CallbackReturn on_shutdown(const rclcpp_lifecycle::State&);
rclcpp_lifecycle::node_interfaces::LifecycleNodeInterface::CallbackReturn on_cleanup(const rclcpp_lifecycle::State&);
};
} // namespace assignments::two::g2_2025_lifecycle_node