rosrospy

ROS topic is not published yet


I have this code which receives data from node (subscribe) and then inside this node I do some mathematical operation, then I want to publish the data to a certain topic.

#!/usr/bin/env python

import rospy
from std_msgs.msg import String, Float32
from math import cos,sin

import sys
import os
import logging
from types import *
import time

class exact_pose():

    def callback_car_yaw(self, data):
        self.car_yaw = data

    def callback_line_pose(self,data):
        self.line_pose = data

        
    def init(self):
      
 
        self.car_yaw = None
        self.line_pose = None
      

    def subscriber(self):
        
 
            
        self.car_yaw_sub = rospy.Subscriber('~car/yaw',Float32, self.callback_car_yaw)
            
        self.line_pose_sub = rospy.Subscriber('~line_pose',Float32, self.callback_line_detect_xL15)

    def publisher(self):

        self.exact_pose_pub = rospy.Publisher('exact_pose',Float32, queue_size=10)
        

        rospy.Rate(1)
        rospy.spin()
      
      
        #sloving for exact pose 

    def calculation(self,):
        while not rospy.is_shutdown():

            self.exact_pose = self.line_pose_sub * cos(self.car_yaw_sub) + self.line_pose_sub * sin(self.car_yaw_sub)
            info1 = Float32()
            info1.data = self.exact_pose
            self.exact_pose_pub.publish(info1)


            rospy.Rate.sleep()
            rospy.spin()


if __name__ == '__main__':
    rospy.init_node('exact_pose', anonymous=True)
    try:
      ne = exact_pose()

    except rospy.ROSInterruptException: pass

so what the code does, subscribe to a topic from a previous node, then do some mathematical operation for these data inside the topics, then publish the last result on separate Node


Solution

  • When requiring asynchronous communication, like in subscribers, multiple threads running in parallel will have to be involved. ROS uses callbacks in order to hide multi-threading required for subscribers from its users. When a new message arrives these callbacks will be added to a callback queue (whose maximum size can be defined for each publisher/subscriber) and then be processed. The way this works differs between C++ and Python:

    In ROS2 the concept is similar but it is termed executors and further extends it with so called callback groups.

    This means that you actually have to register the subscribers and publisher with their callbacks inside a initialisation routine and then you keep your node alive for the desired time, either with a while loop or rospy.spin().

    There is though no hard guarantee that all messages are actually processed. If your throughput is not sufficient (if your callbacks are executed too slowly) you will fill up the queue and eventually start dropping messages. If that is not what you need then have a look at the other communication methods - ROS services and actions. The other communication methods are though a bit more complicated.


    Your code has several errors. You are lucky that Python is translated and not compiled and it never entered the relevant code parts..


    I tried to restructure it and the following code works:

    #!/usr/bin/env python
    
    import rospy
    from std_msgs.msg import Float32
    from math import cos,sin
    
    class exact_pose():
      def __init__(self):
        # Set default values
        self.car_yaw = 0.0
        self.line_pose = 0.0
    
        # Initialise node
        rospy.init_node("emergency_procedure", anonymous=True)
        r = rospy.Rate(1)
    
        # Register topics
        self.car_yaw_sub = rospy.Subscriber('car/yaw',Float32, self.callback_car_yaw)
        self.line_pose_sub = rospy.Subscriber('line_pose',Float32, self.callback_line_pose)
        self.exact_pose_pub = rospy.Publisher('exact_pose',Float32, queue_size=10)
    
        # Repeat the following code in a loop
        while not rospy.is_shutdown():
          # Perform some calculation and publish to topic
          self.exact_pose = self.line_pose * cos(self.car_yaw) + self.line_pose * sin(self.car_yaw)
          info1 = Float32()
          info1.data = self.exact_pose
          self.exact_pose_pub.publish(info1)
          # Sleep for some time
          rospy.Rate.sleep(r)
        return;
    
      def callback_car_yaw(self, data):
        # Copy data to class
        self.car_yaw = data
        return;
    
      def callback_line_pose(self,data):
        # Copy data to class
        self.line_pose = data
        return;
    
    if __name__ == '__main__':
      try:
        # Create instance of class when node is called
        e = exact_pose()
      except rospy.ROSInterruptException:
        pass
    

    Put this code inside your code into your .py-file, open a new console and source the workspace with source devel/setup.bash, then start the roscore, open another console, source the workspace again and launch your Python node rosrun <package> <node>.py. Finally launch another console, source the workspace again and output the topic published by the Python node rostopic echo /exact_pose. If no other node is running this should output you 0.0 every second.