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) ...