Non-mutually-blocking ROS and Qt event loops in the same program

Viewed 36

I am developing a multithreaded ROS application involving Qt::QThread-inherited objects producing signals triggering ROS publishers in the ROS node activated in the main() function. Qt signals and the event loop are handled by Qt::QCoreApplication How can one properly organize the connection between the application objects and runner functions? In the ordinary application Qt::QCoreApplication.exec() and ros::spin() functions are blocking.

1 Answers

The solution is quite easy. It is needed to install SIGINT signal handler function that will control the sequence of starting and stopping event loops:

// POSIX signal handler prototype section
#include <signal.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>

// Qt section
#include <QCoreApplication>

// ROS section
#include <ros/ros.h>

// SIGINT handler function
void handle_shutdown(int s)
{
    ROS_INFO("Shutting down node...");
    ros::shutdown(); // Step 1: stopping ROS event loop
    QCoreApplication::exit(0); // Step 2: stopping Qt event loop
}

int main(int argc, char** args)
{
    // SIGINT handler setup
    struct sigaction sigIntHandler;
    sigIntHandler.sa_handler = handle_shutdown;
    sigemptyset(&sigIntHandler.sa_mask);
    sigIntHandler.sa_flags = 0;
    sigaction(SIGINT, &sigIntHandler, NULL);

    // Instantiating Qt application object
    QCoreApplication app(argc, args);
    // Instantiating ROS node object
    ros::init(argc, args, "witmotion_ros", ros::InitOption::NoSigintHandler);
    ros::NodeHandler node("~");

    // Running ROS non-blocking event loop
    ros::AsyncSpinner spinner(2);
    spinner.start();

    // Running Qt event loop: blocking call
    int result = app.exec();

    // Waiting for signal handler's return
    ros::waitForShutdown();

    // Exit code: from Qt
    return result;
}

The option ros::InitOption::NoSigintHandler instructs ROS application object to skip the installation of its own SIGINT handler. This kind of setup allows using freely both Qt signals, events and ROS callbacks without mutual blocks and race conditions. However, the code model is not totally thread-safe, so it is mandatory to handle synchronization of the data in case of bidirectional exchange.

Related