how to perform a final task before a ROS node shuts down

Sometimes you need to clean up the task by performing a final step before the node closes. For example, when we have a hardware interface and send move commands to the wheelbase, we need to send 0 velocities after the termination of the spinning while loop to stop the robot. In python and more specifically in rospy there this feature.

Why can follow the following python example class structure engaging shutdown hooks as they explained in the official documentation:

import rospy

class Hardware_Interface:
    def __init__(self, selectedBoard):

        ...

        # Housekeeping, cleanup at the end
        rospy.on_shutdown(self.shutdown)

        # Get the connection settings from the parameter server
        self.port = rospy.get_param("~"+self.board+"-port", "/dev/ttyACM0")

        # Get the prefix
        self.prefix = rospy.get_param("~"+self.board+"-prefix", "travel")

        # Overall loop rate
        self.rate = int(rospy.get_param("~rate", 5))
        self.period = rospy.Duration(1/float(self.rate))

        ...

    def shutdown(self):
        rospy.loginfo("Shutting down Hardware Interface Node...")

        try:
            rospy.loginfo("Stopping the robot...")

            self.controller.send(0, 0, 0, 0)
            #self.cmd_vel_pub.publish(Twist())
            rospy.sleep(2)
        except:
            rospy.loginfo("Cannot stop!")

        try:
            self.controller.close()
        except:
            pass
        finally:
            rospy.loginfo("Serial port closed.")
            os._exit(0)

This just an extract from a personal script, please modify it to your needs. I imagine that the on_shutdown will do the trick. Another similar approach comes from my friends in the Robot Ignite Academy in The Construct and seems like that:

import rospy
from geometry_msgs.msg import Twist

class my_class():

    def __init__(self):
        ...
        self.cmd = Twist()
        self.ctrl_c = False
        self.rate = rospy.Rate(10) # 10hz
        rospy.on_shutdown(self.shutdownhook)

    def publish_once_in_cmd_vel(self):

        while not self.ctrl_c:
            ...


    def shutdownhook(self):
        # works better than the rospy.is_shutdown()
        self.ctrl_c = True

    def move_something(self, linear_speed=0.2, angular_speed=0.2):
        self.cmd.linear.x = linear_speed
        self.cmd.angular.z = angular_speed
        self.publish_once_in_cmd_vel()

if __name__ == '__main__':
    rospy.init_node('class_test', anonymous=True)
    ...

Enjoy!