Any way to see IO sooner with OnProcessIO event in ROS2 Launch Description?
Background
Starting with a counter node that looks something like this:
import rclpy
import time
if __name__ == "__main__":
rclpy.init()
node = rclpy.create_node("counter_node")
for n in range(10):
print(n)
time.sleep(1.0)
If I launch the node using ros2 run my_package counter_node
I'll see it output 0, 1, 2, 3, 4, etc. . . about once per second before exiting.
If I launch the same node using ros2 launch like this:
launch_description = LaunchDescription([
Node(package="my_package", node_executable="counter_node"),
RegisterEventHandler(
OnProcessIO(on_stdout=lambda info: print(info.text))
)
])
launch_service = LaunchService()
launch_service.include_launch_description(launch_description)
launch_service.run()
Then the standard out is a little different. I see nothing for 10 seconds, and when my process ends I see all the numbers 0, 1, 2, 3, 4, etc. . . all printed at once. It looks like all the stdout is getting buffered up and printed once the node exits.
If I change my counter node to do
for n in range(10):
print(n)
sys.stdout.flush() # <-- Added this
time.sleep(1.0)
and then run it with launch_service.run()
, I get the once-per-second output again
My Question
Is there a way to get the ros2 run my_package counter_node
behavior with launch_service.run
without modifying the counter node? I'm I overlooking something way simpler?
ros2 run is pretty easy to understand. It's using popen to launch my node, and then polling it with communicate
. ros2 launch's plumbing is a bit harder for me to follow. Is there a way to reach down inside and have it poll the counter_node's IO a little more often so I can see the standard-out a little closer to when it happens without having to modify the node I'm launching? The examples above are deliberately simplified. In my actual application, it's not feasible to add sys.stdout.flush() everywhere