0
$\begingroup$

Rosanswers logo

I'm writing a new node and am following examples on how to do that in python.
This node subscribes to a topic being published from another node (this other node's published topic is being published correctly as verified by "rostopic echo /topicname").
However, the subscriber node doesn't seem to be subscribing correctly to this topic (although the Callback is displaying the information to the command line correctly that it should be taking as input).
I'm in ROS Groovy.

The code is here:

#!/usr/bin/python

#JOE 
#August 2014

#publishes topic ilimb_grip_pub
#subscribes topic ilimb_define_pos
    
import rospy
from std_msgs.msg import String
import socket
#UDP_IP = "129.107.3.95"
UDP_IP = "127.0.0.1" #debug
UDP_PORT = 9000
Program_Name = "./handcontrol"

def callback(data):
    rospy.loginfo(rospy.get_caller_id()+"I heard %s",data.data)

def ilimb_grip_pub():

    # this listens to a user input for a user-defined hand configuration
    rospy.init_node('ilimb_grip_pub', anonymous=True)
    rospy.Subscriber("ilimb_define_pos", String, callback)     

    #this creates the publisher topic
    #pub = rospy.Publisher('ilimb_grip_pub', String) #needs to publish to a IP addr/ port
    #rospy.init_node('ilimb_move', anonymous=True)
    r = rospy.Rate(10) # 10hz


#this loop needs to be modified to publish hand configurations
#based on user input

    while not rospy.is_shutdown():
        print ilimb_define_pos.msg
        #~ define_pos= ilimb_define_pos.split(" ")
        #~ print define_pos
        #~ Digit_ID = define_pos[0]
        #~ Command = define_pos[1]
        #~ 
        #~ Message = "%s %d %s\n"%(Program_Name, Digid_ID, Command)         
                    #~ 
        #~ sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        #~ sock.sendto(Message, (UDP_IP, UDP_PORT))
        #~ 
        #~ rospy.loginfo(Message)
        #~ #pub.publish(str)
        #~ r.sleep()

   # spin() simply keeps python from exiting until this node is stopped
        rospy.spin()
#~ 

    
       
if __name__ == '__main__':
    try:
        ilimb_grip_pub()
    except rospy.ROSInterruptException:
        pass

I'm getting the error:

NameError: global name 'ilimb_define_pos' is not defined.

This is strange as this is the topic to which I am subscribing... any ideas? I'm drawing a blank.


Originally posted by joe.s on ROS Answers with karma: 162 on 2014-08-20

Post score: 0

$\endgroup$

1 Answer 1

0
$\begingroup$

Rosanswers logo

rospy does not create a variable named ilimb_define_pos when you subscribe to that topic. If you want to save the data that is received by the subscriber callback, you should create a global variable and explicitly copy the message into it.

You may want to review the rospy publisher and subscriber tutorial.


Originally posted by ahendrix with karma: 47576 on 2014-08-20

This answer was ACCEPTED on the original site

Post score: 1


Original comments

Comment by joe.s on 2014-08-20:
I only need to manipulate the data... but I need to save a local copy? I ask because I don't remember seeing that in the tutorial. That print statement is for debugging.

Comment by ahendrix on 2014-08-20:
The message data is passed into the callback as an argument; it isn't valid outside the callback unless you assign it into a global variable.

Comment by ahendrix on 2014-08-20:
Alternately, you can do all of your processing inside the callback routine.

Comment by joe.s on 2014-08-20:
Ok. Thank you. I'll see what I can come up with.

Comment by joe.s on 2014-08-21:
Ok. I've done this... but am receiving the error:

NameError: global name 'ilimb_pos' is not defined

... except that's what I thought I was doing in the callback(data) function But, if I uncomment the variable definition in "ilimb_pos none"... then I receive "none" as the output of the print command

Program_Name = "./handcontrol"
#ilimb_pos = None

def callback(data):
    rospy.loginfo(rospy.get_caller_id()+"I heard %s",data.data)
    global ilimb_pos
    ilimb_pos = data

def ilimb_grip_pub():

    # this listens to a user input for a user-defined hand configuration
    rospy.init_node('ilimb_grip_pub', anonymous=True)
    rospy.Subscriber("ilimb_define_pos", String, callback)     

    #this creates the publisher topic
    #rospy.init_node('ilimb_move', anonymous=True)
    r = rospy.Rate(10) # 10hz


    while not rospy.is_shutdown():
        #print Callback_Data
        print ilimb_pos

Comment by ahendrix on 2014-08-21:
I would expect it to work if you uncomment the variable definition in the top-level scope. That said, I would expect it to print None until it receives the first message.

Comment by joe.s on 2014-08-21:
that does "fix" the issue... but that brings up another problem. I'm wanting to manipulate the subscribed data and expect it, "data" to be of type "string".... (should I start a new thread?) Here's the code I'm currently looking at:

ilimb_pos = None
l1 = []

def callback(data):
    rospy.loginfo(rospy.get_caller_id()+"I heard %s",data.data)
    global ilimb_pos
    ilimb_pos = data
    print ilimb_pos
        
    for elem in ilimb_pos:
        l1.extend(elem.strip().split(" "))
    print l1
    

I get this error:

for elem in ilimb_pos:
TypeError: 'String' object is not iterable

I'm researching now but could use a point in the right direction.

Comment by ahendrix on 2014-08-21:
Please review the rospy tutorial and the definition for a string message again. The object your callback is receiving is a std_msgs/String object, which contains a single member called data which is a string. You log statement gets this right.

Comment by joe.s on 2014-08-21:
I have done that... and that must be where I'm not understanding something... If it's a String object, why can I not manipulate it like a 'string'?
"Strings" are iterable in python. But does that mean that "std_msgs/String"'s are not iterable? If so, then I'm even more lost as to how to proceed and do what I need to do... And thanks for the help so far. It's appreciated.

Comment by ahendrix on 2014-08-21:
You want data.data

Comment by joe.s on 2014-08-21:
This did it...

def callback(data):
    rospy.loginfo(rospy.get_caller_id()+"I heard %s",data.data)
    global ilimb_pos
    ilimb_pos = data
    define_pos =  str(ilimb_pos).split(' ')[1:3] 

Thank you for the hand holding. It's appreciated.

Comment by ahendrix on 2014-08-21:
As a final note, you should probably be using a custom message type instead of manually packing data into a string and unpacking it on the other side. ROS can already do this for you, and validate that the sender and receiver agree on the data type and format of the connection.

Comment by joe.s on 2014-08-22:
Thank you. I'll end up going that route on version 2. I'll need to send more than a single "line" at a time then... this is just a proof of concept... but that version of the node will communicate out via a completely different method as well which is why I started here for the quick and dirty version.

$\endgroup$

Your Answer

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