ROS Resources: Documentation | Support | Discussion Forum | Index | Service Status | ros @ Robotics Stack Exchange
Ask Your Question
0

Threads when using ros2 and python

asked 2021-09-10 05:09:30 -0500

fnax8902 gravatar image

updated 2021-09-10 05:25:11 -0500

Hello, I want to implement a planner, which needs continous updates from other vehicles. Therefore the planner should be started in its own thread. I have read that in rospy with ROS1 each timer callback created a own thread. So I tried this in ROS2 as well, but it seems, that my program is stuck in the timer callback, where I create my planner. Is there another way to archive this?

class UploadPlan(Node):

    def __init__(self):
        super().__init__('upload_plan')
        self.publisher_ = self.create_publisher(String, '/topic', 10)
        self.subscription = self.create_subscription(
            String,
            '/topic',
            self.sub_callback,
            10)
        timer_period = 1  # seconds
        self.timer = self.create_timer(timer_period, self.timer_callback)

    def timer_callback(self):
        blocking_function() # needs to be in its own thread
        self.timer.cancel()

    def sub_callback(self, msg):
        print("callback")


def main(args=None):
    rclpy.init(args=args)

    upload_plan = UploadPlan()

    rclpy.spin(upload_plan)
    upload_plan.destroy_node()
    rclpy.shutdown()


if __name__ == '__main__':
    main()

Thanks.

edit retag flag offensive close merge delete

Comments

There's definitely ways to achieve what you want to do. Please edit your question to provide a compact example for us to be able to help you.

tfoote gravatar image tfoote  ( 2021-09-10 05:11:27 -0500 )edit

I added an example

fnax8902 gravatar image fnax8902  ( 2021-09-10 05:25:26 -0500 )edit

Why does the planner calculation need to be in its own thread?

Jaron gravatar image Jaron  ( 2021-09-10 15:02:10 -0500 )edit

1 Answer

Sort by ยป oldest newest most voted
0

answered 2021-09-10 08:43:36 -0500

Jaron gravatar image

updated 2021-09-10 15:01:02 -0500

One thing to note is that the timer is not creating it's own thread. In your example, the reason your timer_callback is not ending is because you're expecting that function to be in it's own thread, which it is not. All the timer does is create callback events that an executor would pick up to run. In your example, you create the executor when you call rclpy.spin() which initializes the default, single-threaded executor, adds the node upload_plan to it, and then calls spin() on that executor. Whenever your subscription object or timer object need to respond to do something, they create an event, or callback, for the executor to actually do the executing.

What you're trying to do is wrong because your events should not be continuous, blocking events, lest they clog up the executor from being able to do other things. I don't quite understand why you think you need a separate thread inside the timer_callback. I'm guessing from your example that you're are simply trying to create a periodic calculation that listens to topics and publishes a calculation as the given timer_period. To do that all you would need to do is modify your blocking function to be one run of that calculation and then publish that result for the other vehicles to use. It would look something like this:

class UploadPlan(Node):

    def __init__(self):
        super().__init__('upload_plan')
        self.publisher_ = self.create_publisher(String, '/topic', 10)
        self.subscription = self.create_subscription(
            String,
            '/topic',
            self.sub_callback,
            10)
        self.state = "foo"
        timer_period = 1  # seconds
        self.timer = self.create_timer(timer_period, self.timer_callback)

    def timer_callback(self):
        if self.state == 'bar':
            self.publisher_.publish(String("foobar"))
        else:
            self.publisher_.publish(String("barfoo"))

    def sub_callback(self, msg):
         self.state = msg.data

def main(args=None):
    rclpy.init(args=args)

    upload_plan = UploadPlan()

    rclpy.spin(upload_plan)
    upload_plan.destroy_node()
    rclpy.shutdown()


if __name__ == '__main__':
     main()
edit flag offensive delete link more

Comments

I know about the multi-threaded executer in cpp. How do I use it in python?

fnax8902 gravatar image fnax8902  ( 2021-09-10 12:02:47 -0500 )edit

Question Tools

3 followers

Stats

Asked: 2021-09-10 05:09:30 -0500

Seen: 3,579 times

Last updated: Sep 10 '21