0
$\begingroup$

I have made a node to run some calculations using data from another topic (odom in this case) and publish them to another topic. How do I set the rate of this node to be slower than the subscribed topic?

Here is what I have but I can't get it to work:

#!/usr/bin/env python3

import rclpy
from rclpy.node import Node
import traceback

from std_msgs.msg import Float64MultiArray
from nav_msgs.msg import Odometry


class CalculatedNode(Node):

    def __init__(self):
        super().__init__('calculated_node')
        # Create publisher
        self.calculated_node = self.create_publisher(Float64MultiArray, '/calculated_stuff', 10)

        # Subscribe to node
        self.subscription = self.create_subscription(
            Odometry,
            '/odom',
            self.update_calculations,
            1)

    def update_calculations(self, msg):
        try:
            # DO SOME CALCULATIONS WITH MSG DATA
            # [...]
            # Publish Odom
            self.calculated_node.publish(Float64MultiArray())
        except Exception as e: 
            traceback.print_exc()
            print(self.get_clock().now())
            # print(e)
        

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

    try:
        rate = calculated_node.create_rate(2)
        rclpy.spin(calculated_node)
        
        while rclpy.ok:
            rate.sleep()
    except KeyboardInterrupt:
        pass

    calculated_node.destroy_node()
    rclpy.shutdown()

if __name__ == '__main__':
    main()

This was simpler than I though. Here is an example using the chatter tutorial:

#!/usr/bin/env python3
import rclpy
from rclpy.node import Node

from std_msgs.msg import String


class MinimalSubscriber(Node):

    def __init__(self):
        super().__init__('minimal_subscriber')
        self.msg_store = None

        self.subscription = self.create_subscription(
            String,
            'topic',
            self.listener_callback,
            1)
        self.subscription  # prevent unused variable warning

        self.create_timer(2, self.timed_call)

    def listener_callback(self, msg):
        self.msg_store = msg

    def timed_call(self):
        self.get_logger().info('I heard: "%s"' % self.msg_store.data)

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

    minimal_subscriber = MinimalSubscriber()
    rclpy.spin(minimal_subscriber)
    minimal_subscriber.destroy_node()
    rclpy.shutdown()


if __name__ == '__main__':
    main()

This however has an issue. The timed callback "timed_call" gets called every other trigger event. This is the output:

[INFO] [1683201706.818698434] [minimal_subscriber]: I heard: "Hello World: 6"
[INFO] [1683201708.805167207] [minimal_subscriber]: I heard: "Hello World: 10"
[INFO] [1683201710.804572917] [minimal_subscriber]: I heard: "Hello World: 14"
[INFO] [1683201712.804249021] [minimal_subscriber]: I heard: "Hello World: 18"
$\endgroup$

1 Answer 1

0
$\begingroup$

I recommend using a timer to trigger a callback at the frequency you want to publish. And in that callback send the output message based on stored data.

In the subscribers callback you should do any necessary computation and then save the resulting data for the timer callback to access.

$\endgroup$
4
  • $\begingroup$ would you be able to give an example? I understand what you mean but I'm not sure how to implement it (conceptually). Do I need callback groups? $\endgroup$
    – guidout
    Commented Apr 30, 2023 at 11:54
  • $\begingroup$ Please give it a try and ask concrete questions about what you don't understand. You'll learn much better that way. You don't need to worry about callback groups until you want to multithread which is unnecessary for what you've outlined. $\endgroup$
    – Tully
    Commented Apr 30, 2023 at 18:18
  • $\begingroup$ ok, that was simpler than I thought. The blocking spin() was throwing me off. I updated the question with a working example but it looks like the "timed_call" gets called every other "time". If I set x seconds in the timer, it get executed every 2*x seconds. Not sure why $\endgroup$
    – guidout
    Commented May 4, 2023 at 11:59
  • 1
    $\begingroup$ Your code as presented is self consistent you set the period to be 2 seconds and the console output shows the timestamp as very close to every 2 seconds. The output number is incrementing by 4. But I would guess that the publisher is incrementing twice a second not just every second. $\endgroup$
    – Tully
    Commented Jun 5, 2023 at 4:02

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.