Hi,
In ROS1, I can use rospy.on_shutdown(shutdown_hook) to do something before the node is down like stopping the AMR
But I do not see the function in ROS2.
How can I do the same function in ROS2?
Thanks
Hi,
In ROS1, I can use rospy.on_shutdown(shutdown_hook) to do something before the node is down like stopping the AMR
But I do not see the function in ROS2.
How can I do the same function in ROS2?
Thanks
In ROS 2, there isn’t a direct equivalent to rospy.on_shutdown() for registering a shutdown hook. But you can do something similar by structuring your node’s lifecycle management carefully:
def shutdown_hook(self):
# Place your pre-shutdown logic here
self.get_logger().info('Performing pre-shutdown actions...')
# Example: Stop the AMR
# self.stop_amr()
def main(args=None):
rclpy.init(args=args)
my_node = MyCustomNode()
try:
rclpy.spin(my_node)
except KeyboardInterrupt:
pass
finally:
# Call the shutdown hook before destroying the node
my_node.shutdown_hook()
my_node.destroy_node()
rclpy.shutdown()
if __name__ == '__main__':
main()
Hi, I was busy so could not come back sooner.
This time I will keep up until the end
I try your suggestion but it does not work.
It said: Failed to publish log message to rosout: publisher’s context is invalid, at ./src/rcl/publisher.c:389
And the robot does not stop
Could you check my code?
#! /usr/bin/env python3
import rclpy
from rclpy.node import Node
from rclpy.qos import QoSProfile, QoSReliabilityPolicy, QoSDurabilityPolicy
from geometry_msgs.msg import Twist
from std_msgs.msg import Int32
import os, sys, argparse
from pathlib import Path
from glob import glob
import time
from datetime import datetime
import logging
class TopicPublisher(Node):
def __init__(self, nodeName):
self.nodeName = nodeName
super().__init__(node_name=self.nodeName)
self.get_logger().set_level(rclpy.logging.LoggingSeverity.INFO)
self.ctrlC = False
# region init
self.publisher = self.create_publisher(
msg_type = Twist,
topic = 'cmd_vel',
qos_profile = QoSProfile(
depth = 10,
reliability = QoSReliabilityPolicy.RELIABLE, # BEST_EFFORT: sensor | RELIABLE: control
durability = QoSDurabilityPolicy.VOLATILE # TRANSIENT_LOCAL: latch | VOLATILE: no latch
)
)
self.twist = Twist()
self.timer = self.create_timer(2, self.timer_callback)
# endregion
def shutdown_callback(self):
self.ctrlC = True
self.twist.linear.x = 0.0
self.twist.angular.z = 0.0
self.get_logger().warning(f"{self.nodeName} is shutting down")
self.publisher.publish(self.twist)
self.get_logger().warning(f"self.twist.data: {self.twist}")
def timer_callback(self):
self.twist.linear.x = 0.2
self.twist.angular.z = 0.2
self.publisher.publish(self.twist)
self.get_logger().info(f"self.twist.data: {self.twist}")
def main(args=None):
rclpy.init(args=args)
topicPublisher = TopicPublisher("topic_publisher_node")
try:
rclpy.spin(topicPublisher)
except KeyboardInterrupt:
pass
finally:
topicPublisher.shutdown_callback()
topicPublisher.destroy_node()
rclpy.try_shutdown()
if __name__ == '__main__':
main()
# for key, value in os.environ.items():
# print(f"{key} -- {value}")
Please check and help me
Thanks.
Hi, it’s not that the shutdown hook doesn’t work, it seems like there is an issue with the logging. Does it work without the logging? your logic seems correct
I tried several times but it is the same. Please check
#! /usr/bin/env python3
import rclpy
from rclpy.node import Node
from rclpy.qos import QoSProfile, QoSReliabilityPolicy, QoSDurabilityPolicy
from geometry_msgs.msg import Twist
from std_msgs.msg import Int32
import os, sys, argparse
from pathlib import Path
from glob import glob
import time
from datetime import datetime
import logging
class TopicPublisher(Node):
def __init__(self, nodeName):
self.nodeName = nodeName
super().__init__(node_name=self.nodeName)
self.get_logger().set_level(rclpy.logging.LoggingSeverity.INFO)
self.ctrlC = False
# region init
self.publisher = self.create_publisher(
msg_type = Twist,
topic = 'cmd_vel',
qos_profile = QoSProfile(
depth = 10,
reliability = QoSReliabilityPolicy.RELIABLE, # BEST_EFFORT: sensor | RELIABLE: control
durability = QoSDurabilityPolicy.VOLATILE # TRANSIENT_LOCAL: latch | VOLATILE: no latch
)
)
self.twist = Twist()
self.timer = self.create_timer(2, self.timer_callback)
# endregion
def shutdown_callback(self):
self.ctrlC = True
self.twist.linear.x = 0.0
self.twist.angular.z = 0.0
# self.get_logger().warning(f"{self.nodeName} is shutting down")
self.publisher.publish(self.twist)
# self.get_logger().warning(f"self.twist.data: {self.twist}")
def timer_callback(self):
self.twist.linear.x = 0.2
self.twist.angular.z = 0.2
self.publisher.publish(self.twist)
self.get_logger().info(f"self.twist.data: {self.twist}")
def main(args=None):
rclpy.init(args=args)
topicPublisher = TopicPublisher("topic_publisher_node")
try:
rclpy.spin(topicPublisher)
except KeyboardInterrupt:
pass
finally:
topicPublisher.shutdown_callback()
topicPublisher.destroy_node()
rclpy.try_shutdown()
if __name__ == '__main__':
main()
# for key, value in os.environ.items():
# print(f"{key} -- {value}")
This topic was automatically closed after 6 days. New replies are no longer allowed.
Does anyone help me, please?
The node in your script isn’t shutting down because shutdown_callback()
is never called unless a KeyboardInterrupt
exeception occurs.
A node will continue running with rclpy.spin()
until a shutdown event is triggered, like pressing Ctrl+C
. The shutdown function is only invoked in the finally
block here, so there is no condition to break the rclpy.spin()
.
I assume you are expecting an automatic shutdown without manual intervention, so you need to add some logic to trigger this event. More specifically, to break timer_callback()
.
Here you can check the shutdown documentation and different ways you can use it, as well as some examples in scripts:
https://docs.ros2.org/galactic/api/rclpy/api/init_shutdown.html
I want every time the rclpy shut down, it will execute a function before really shutdown like rospy.on_shutdown(function) in ROS1.
In Ros1, after I register a function in rospy.on_shutdown(function). If I press Ctrl+C, it will execute function() then stopping. So I want to do the same in ROS2.
I follow your guide but I press Ctrl + C, ros2 can execute the function() but commands as sending messages to a topic, logging, … do not work. It raise error like images I sent. That is my problem and I want to get help
I’ve done a deep dive to see what is happening here, and it seems Humble and more recent distros are having issues precisely in that area. It seems like it’s not something you are coding incorrectly, but rather a racy condition that happens that prevents you from publishing any ROS 2 information when there is a keyboardinterrupt.
Here is an interesting open issue related to this:
I don’t know how to go around this issue. I think this issue is related so let’s see if @albertoezquerro has a workaround.