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

Using python classes to access information in other functions

asked 2021-01-13 16:43:13 -0500

PGTKing gravatar image

updated 2021-01-13 19:39:50 -0500

jayess gravatar image

In these functions

def callback(data):
    #rospy.loginfo(data.position[1])
    print(data.position[0])

def listener():

    rospy.init_node('listener')

    rospy.Subscriber('/rrbot/joint_states', JointState, callback) 
    rospy.spin()


def talker():

    pub = rospy.Publisher('/rrbot/joint1_position_controller/command', Float64, queue_size=10)
    rospy.init_node('talker', anonymous=True)
    rate = rospy.Rate(1) # 10hz
    while not rospy.is_shutdown():
        #hello_str = "hello world %s" % rospy.get_time()
        #force = random.choice([-1,1])
        force = 0
        rospy.loginfo(force)
        pub.publish(force)
        rate.sleep()

The talker function works fine as it publishes the position to the robot, and the callback and listener function work fine and reads the correct position over time every 10hz. But they only work separately in two different terminals but I need access to both the force that is being published and the position that is being subscribed to to run a machine learning algorythm so I made this class

class RobotControl():
    def __init__(self):
        rospy.init_node('robot_control_node', anonymous=True)
        self.talker = rospy.Publisher('/rrbot/joint1_position_controller/command', Float64, queue_size=10)
        self.rate = rospy.Rate(1)
        self.sub = rospy.Subscriber('/rrbot/joint_states', JointState, self.callback)
        self.force = random.choice([-1,1])
    def give_force(self):
        while not rospy.is_shutdown():
            #hello_str = "hello world %s" % rospy.get_time()
            #force = random.choice([-1,1])
            #force = 0
            #rospy.loginfo(self.force)
            self.talker.publish(self.force)
            self.rate.sleep()
    def callback(self,data):
        print(data.position[0])
        print(self.force)

r = RobotControl()
r.callback()

I am having trouble with the force not changing between 1 and -1 it just sticks to either or. and I'm getting

TypeError: callback() missing 1 required positional argument: 'data'

here is an example of the output

-1

-3.0659357154670257

-1

-3.0659357154670257

-1

-3.0659357154670257

-1

-3.0659357154670257

-1

-3.0659357154670257

-1
edit retag flag offensive close merge delete

2 Answers

Sort by ยป oldest newest most voted
1

answered 2021-01-14 08:57:55 -0500

tryan gravatar image

@jayess is correct on all points. You set self.force = random.choice([-1,1]) only once, and you generally don't need to call subscriber callbacks directly. The error is from your (unnecessary) direct call, while the output is from the subscriber calls. Furthermore, you never actually call give_force(), so it's not publishing self.force. Judging from your code, you'd like your node to publish a random force continuously, then print both the current force and position when it receives a new JointState message. There are other ways to lay out a node class, but here's an example:

class RobotControl():
    def __init__(self):
        rospy.init_node('robot_control_node', anonymous=True)
        self.talker = rospy.Publisher('/rrbot/joint1_position_controller/command', Float64, queue_size=10)
        self.sub = rospy.Subscriber('/rrbot/joint_states', JointState, self.callback)
        self.force = None  # Generally, it's good to initialize member variables.  What if callback() is called before give_force()?

        rate = rospy.Rate(1)
        while not rospy.is_shutdown():
            self.give_force()
            rate.sleep()

    def give_force(self):
        self.force = random.choice([-1,1])  # Changes force every time, right before publishing
        self.talker.publish(self.force)

    def callback(self,data):
        print(data.position[0])
        print(self.force)  # Prints value defined elsewhere

if __name__=="__main__":
    r = RobotControl()

As an aside, callback() prints the _current_ force value when it's called, so the printed force and position don't have a guaranteed temporal relationship. There are ways to deal with that, but that may be outside the scope here.

edit flag offensive delete link more

Comments

so at the bottom you have r = RobotControl() this means every function in the class is runs simultaneously?

PGTKing gravatar image PGTKing  ( 2021-01-14 15:01:07 -0500 )edit

Not exactly. That just instantiates the class, calling __init__(), which in turn calls give_force() in a loop. The subscriber calls callback() any time it receives a message on the subscribed topic. At the end of the loop, rate.sleep() actually allows the callback(s) to execute.

tryan gravatar image tryan  ( 2021-01-14 15:23:59 -0500 )edit
1

got it!! appreciate the help!

PGTKing gravatar image PGTKing  ( 2021-01-14 15:38:38 -0500 )edit
2

answered 2021-01-13 19:50:43 -0500

jayess gravatar image

In your definition of the RobotControl class, you never update self.force. It's set in your __init__ method, but it never changes. You'll need to update it somehow, either in your callback or somewhere else.

For the TypeError, you're explicitly calling your callback function and you're not passing it any parameters. First, you don't explicitly call a callback function. The callback function will be called when a message is received on the topic that your subscriber subscribes to receives a message. Second, if you were to actually call it you'd need to pass the data parameter. But you don't need to call it so remove the

r.callback()

line.

edit flag offensive delete link more

Question Tools

1 follower

Stats

Asked: 2021-01-13 16:43:13 -0500

Seen: 1,002 times

Last updated: Jan 14 '21