1

My gazebo model can move to a given goal destination. so far the goal was given by user input as such:

goal_pose.x = float(input("Set your x goal: "))
goal_pose.y = float(input("Set your y goal: "))

I want to send the goal destination through a node and not by user input. so I created another node that publish some random goal destination.

The problem is that when i try to subscribe to that node, it only subscribe after i use input() command.

the code that doesnt work:

        print("self.goal , is:") 
        print(self.goal_pose.x, self.goal_pose.y)
        print("self.goal , is:")
        print(self.goal_pose.x, self.goal_pose.y)

output:

self.goal , is:
(0.0, 0.0)
self.goal , is:
(0.0, 0.0)

the code that does work:

        print("self.goal , is:")
        print(self.goal_pose.x, self.goal_pose.y)
        input("type something and press enter: ")
        print("self.goal , is:")
        print(self.goal_pose.x, self.goal_pose.y)

output:

self.goal , is:
(0.0, 0.0)
type something and press enter: 22
self.goal , is:
(5.0, 6.0)

I would like to know, what is the reason for this behavior and how to fix it?

Attached some essentials of the code:

class oferbot_controller:

    def __init__(self):
        rospy.init_node(const.MOVE_NODE_NAME, anonymous=True)
        self.velocity_publisher = rospy.Publisher(const.CMD_VEL_TOPIC, Twist, queue_size=10)
        self.odom_subscriber = rospy.Subscriber(const.ODOMETRY_TOPIC,Odometry, self.update_odom)
        self.goal_subscriber = rospy.Subscriber(const.GOAL_POSE_TOPIC,Pose,self.update_goal)
        self.odom = Odometry()
        self.goal_pose = Pose()
        self.vel_msg = Twist()
        self.teta = float()
        self.rate = rospy.Rate(10)
        
        


    def update_goal(self,data): 
        self.goal_pose = data
        self.goal_pose.x = round(self.goal_pose.x, 4)
        self.goal_pose.y = round(self.goal_pose.y, 4)

    
    
    def move2goal(self):
        
        
        print("self.goal , is:")
        print(self.goal_pose.x, self.goal_pose.y)
        input("type something and press enter: ")
        print("self.goal , is:")
        print(self.goal_pose.x, self.goal_pose.y)


        while calc.euclidean_distance(self.odom,self.goal_pose) >= const.DISTANCE_TOLERANCE:
            ## Make the robot move accordingly ##

        # Stopping our robot after the movement is over.
        self.stop_the_bot()
        rospy.spin()

if __name__ == '__main__':
    try:
        x = oferbot_controller()
        x.move2goal()
    except rospy.ROSInterruptException:
        pass

the publisher node runs in a different terminal. the publisher code:

rospy.init_node('point_goal_publisher')

point_goal_pub = rospy.Publisher(const.GOAL_POSE_TOPIC, Pose, queue_size=10)
point_goal = Pose()
point_goal.x = const.POINT_X
point_goal.y = const.POINT_Y
rate = rospy.Rate(10)
print("Publishing point goal:")
print("x goal = ", point_goal.x ,"y goal = ", point_goal.y)
while not rospy.is_shutdown():
    point_goal_pub.publish(point_goal)
    rate.sleep()
oferb
  • 91
  • 5
  • 1
    You need to provide more code. Specifically where your subscribers are getting created and the callbacks. Subs will connect as soon as you call `rospy.Subscriber`. That doesn't mean data is being received, though. – BTables Sep 14 '21 at 15:43

2 Answers2

1

You can try to call self.move2goal() directly in the update_goal() function to be sure to received data before execution.

vachmara
  • 126
  • 6
1

You're calling print() very soon after actually creating subscribers that are probably only coming in at <50Hz. This means there's a very high chance that the subscribers will not have received any data by the time you query the msg variable. The input call gives it enough time to actually receive a message; this doesn't specifically force it to receive anything. What you should do is for it to wait for a valid goal like this:

class oferbot_controller:

    def __init__(self):
        rospy.init_node(const.MOVE_NODE_NAME, anonymous=True)
        self.velocity_publisher = rospy.Publisher(const.CMD_VEL_TOPIC, Twist, queue_size=10)
        self.odom_subscriber = rospy.Subscriber(const.ODOMETRY_TOPIC,Odometry, self.update_odom)
        self.goal_subscriber = rospy.Subscriber(const.GOAL_POSE_TOPIC,Pose,self.update_goal)
        self.odom = Odometry()
        self.goal_pose = None
        self.vel_msg = Twist()
        self.teta = float()
        self.rate = rospy.Rate(10)
        
        


    def update_goal(self,data): 
        self.goal_pose = data
        self.goal_pose.x = round(self.goal_pose.x, 4)
        self.goal_pose.y = round(self.goal_pose.y, 4)

    
    
    def move2goal(self):
        
        while self.goal_pose == None:
            self.rate.sleep()
        
        print("self.goal , is:")
        print(self.goal_pose.x, self.goal_pose.y)


        while calc.euclidean_distance(self.odom,self.goal_pose) >= const.DISTANCE_TOLERANCE:
            ## Make the robot move accordingly ##

        # Stopping our robot after the movement is over.
        self.stop_the_bot()
        rospy.spin()

if __name__ == '__main__':
    try:
        x = oferbot_controller()
        x.move2goal()
    except rospy.ROSInterruptException:
        pass
BTables
  • 4,413
  • 2
  • 11
  • 30
  • When [comparing to `None`](https://www.python.org/dev/peps/pep-0008/#programming-recommendations), use `is` and not `==`. – MatBBastos Sep 14 '21 at 16:42
  • It is true that across the board `is` should be used since custom comparison operators are possible. It should be noted that here we know this isn’t the case for ros messages so functionally it doesn’t matter – BTables Sep 14 '21 at 17:16
  • Not about the functionality exactly. It's best practices, as defined by the major reference of that in Python (PEP8). Therefore, it is always the case to make those notes, even more to make proper suggestions that take this into account. – MatBBastos Sep 14 '21 at 17:24
  • I understand what you're saying, but PEP8 is not absolute and its standards do not completely apply to 100% of situations. Project specific guidelines take precedence within the scope of a project. For example, if you're guaranteed that standard message types have no custom operators defined(like above) it's perfectly fine to have a guideline that says you can use `==` in that specific case. – BTables Sep 14 '21 at 17:36
  • You're right. But if there is no reason to do it differently (as a specific project guideline, as mentioned), there is no point in going explicitly against the convention. It also becomes imperative to check for custom operators, with can be a source of annoyance. – MatBBastos Sep 14 '21 at 18:08
  • Also, I'd say that even when project guidelines "go against" PEP8, it's still 'covered', as PEP8 states "_A style guide is about consistency. Consistency with this style guide is important. Consistency within a project is more important. Consistency within one module or function is the most important._" – MatBBastos Sep 14 '21 at 18:10
  • In the cases I mention it most definitely is not imperative to check because a guarantee means any such check would be redundant. PEP8 also states *In the event of any conflicts, such project-specific guides take precedence for that project.*, so it's certainly not always covered. – BTables Sep 14 '21 at 18:18