How can I properly call a method from its callback method within a class?

Question:

I Have a code with two functions. Function ‘send_thread’ and Function ‘receive_thread’ which is the callback of ‘send_thread’. What I want to do is to run ‘send_thread’, this activates ‘receive_thread’ and once it’s over repeat it all again. To do so, I have come up with the code below. This is not giving the desired results, since the ‘send_thread’ gets called again but doesn’t activate the callback anymore. Thank you in advance for your help.

I have noticed, that the function gets called at the end of the receive_thread and runs for the amount of time that I wait in the send_thread (rospy.sleep()). I does never activate the callback again after the first try though.

import rospy
import pepper_2d_simulator
import threading

class TROS(object):
    def __init__(self):
        self.cmd_vel_pub = rospy.Publisher('cmd_vel',Twist)
        self.event = threading.Event()

    def send_thread(self):
        #send commmand
        self.event.set()
        sequence = [[1,0,0.05],[0,0,0],[0,0,0.1292]]
        for cmd in sequence:
            rospy.Rate(0.5).sleep()
            msg = Twist()
            msg.linear.x = cmd[0]
            msg.linear.y = cmd[1]
            msg.angular.z = cmd[2]
            t = rospy.get_rostime()
            self.cmd_vel_pub.publish(msg)
        self.event.clear()
        rospy.sleep(1)

    def receive_thread(self,msg):
        #if something is being send, listen to this
        if self.event.isSet():
            frame_id = msg.header.frame_id
            self.x_odom = msg.pose.pose.position.x
            self.y_odom = msg.pose.pose.position.y
            self.z_odom = msg.pose.pose.position.z
            self.pos_odom = [self.x_odom,self.y_odom,self.z_odom,1]
            self.ang_odom = msg.pose.pose.orientation.z
            self.time = msg.header.stamp.secs + msg.header.stamp.nsecs 
            #some transformations here to get self.trans...         
        else:
            #after self.event() is cleared, rename and run again
            self.x_odom = self.trans_br_x
            self.y_odom = self.trans_br_y
            self.ang_odom = self.rot_br_ang
            self.send_thread()

    def init_node(self):
        rospy.init_node('pepper_cmd_evaluator',anonymous = True)                   
        rospy.Subscriber('odom',Odometry,self.receive_thread)

if __name__ == '__main__':
    thinking = Thinking()
    thinking.init_node()
    thinking.send_thread()

The expected result is that I am able to loop this two function so that I call send_thread, this activates receive thread. Then send_thread stops, receive_thread stops and activates the send_thread again. I want to do this 10 times.
Asked By: Chusikowski

||

Answers:

I have now figured out how to this. I will post my solution in case anyone else runs into a similar problem. The working solution I came up with is pretty simple. I created a self.flag variable and alternatively set it to True and False in the send_thread and callback respectively. The code:

import rospy
import pepper_2d_simulator
import threading

class TROS(object):
    def __init__(self):
        self.cmd_vel_pub = rospy.Publisher('cmd_vel',Twist)
        self.event = threading.Event()
        self.count = 0
        self.flag = True

    def send_thread(self):
        while self.count < 10:
            if self.flag:
                self.count = self.count + 1
                #send commmand
                self.event.set()
                sequence = [[1,0,0.05],[0,0,0],[0,0,0.1292]]
                for cmd in sequence:
                    rospy.Rate(0.5).sleep()
                    msg = Twist()
                    msg.linear.x = cmd[0]
                    msg.linear.y = cmd[1]
                    msg.angular.z = cmd[2]
                    t = rospy.get_rostime()
                    self.cmd_vel_pub.publish(msg)
                self.event.clear()
                rospy.sleep(0.3)
                self.flag = False
        rospy.signal_shutdown('Command finished')

    def receive_thread(self,msg):
        #if something is being send, listen to this
        if self.event.isSet():
            frame_id = msg.header.frame_id
            self.x_odom = msg.pose.pose.position.x
            self.y_odom = msg.pose.pose.position.y
            self.z_odom = msg.pose.pose.position.z
            self.pos_odom = [self.x_odom,self.y_odom,self.z_odom,1]
            self.ang_odom = msg.pose.pose.orientation.z
            self.time = msg.header.stamp.secs + msg.header.stamp.nsecs 
            #some transformations here to get self.trans...         
        else:
            #after self.event() is cleared, rename and run again
            self.x_odom = self.trans_br_x
            self.y_odom = self.trans_br_y
            self.ang_odom = self.rot_br_ang
            self.flag = True

    def init_node(self):
        rospy.init_node('pepper_cmd_evaluator',anonymous = True)                   
        rospy.Subscriber('odom',Odometry,self.receive_thread)

if __name__ == '__main__':
    thinking = Thinking()
    thinking.init_node()
    thinking.send_thread()
Answered By: Chusikowski

I wanted to ask something about your program. When you created a callback for your subscriber within the class, were you running into an error called "positional argument"?
What I understood from it is that in declaring arguments for the callback function the argument ‘msg’ should be first and ‘self’ second. But when I do that it says otherwise. Would you know what it might be?/

Answered By: Mojiz
Categories: questions Tags: , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.