如何将从 rospy.Subscriber 数据获得的数据提供给变量? [英] How to feed the data obtained from rospy.Subscriber data into a variable?

查看:151
本文介绍了如何将从 rospy.Subscriber 数据获得的数据提供给变量?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我编写了一个示例订阅者.我想将从 rospy.Subscriber 获得的数据提供给另一个变量,以便我稍后可以在程序中使用它进行处理.目前我可以看到订阅者正在运行,因为当我使用 rospy.loginfo() 函数时,我可以看到正在打印的订阅值.虽然我不知道如何将这些数据存储到另一个变量中.我曾尝试使用赋值运算符="将其直接赋值给变量,但出现错误.

我尝试使用 rospy.loginfo 编写回调函数来打印订阅对象的位置数据.我已经订阅了 JointState 并且它包含头、位置、速度和努力数组.使用 rospy.loginfo 我可以验证订阅者是否正在订阅.但是当我试图将它直接分配给一个变量时,我得到了一个错误.

我正在显示来自回调函数的日志信息,如下所示

def 回调(数据):rospy.loginfo(data.position)全球聆听听 = rospy.Subscriber("joint_states", JointState,打回来)rospy.spin()

这很好用.但是当我稍微修改代码以分配订阅的值时,我收到以下错误,即

 listen1 = rospy.Subscriber("joint_states", JointState,回调=无)听=听1.位置#rospy.loginfo(听)打印(听)rospy.spin()```错误如下,```listen = listen1.positionAttributeError:订阅者"对象没有位置"属性

这是我在程序中定义的节点,

 #rospy.loginfo(msg.data)全局tactile_statestactile_states = data.data定义联合回调(数据):#rospy.loginfo(data.position)全局 g_joint_states全局 g_position全局 g_pos1g_joint_states = 数据#for i in len(data.position):#g_position[i] = data.position[i]g_position = data.position如果 len(data.position) >0:print("联合状态大于0")g_pos1 = data.position[0]#print(g_position)defjoint_modifier(*args):#choice 描述节点应该做什么,无论是作为发布者还是订阅联合状态或触觉传感器rospy.init_node('joint_listener_publisher',anonymous=True)pub1 = rospy.Publisher('joint_states', JointState, queue_size = 10)如果(len(参数)> 1):选择 = args[0]关节名称 = args[1]位置 = args[2]别的:选择 = args[0]如果(选择== 1):速率 = rospy.Rate(1)机器人配置 = JointState()robots_configuration.header = Header()robots_configuration.name = [joint_name]robots_configuration.position = [位置]robots_configuration.velocity = [10]机器人配置.努力 = [100]虽然不是 rospy.is_shutdown():robots_configuration.header.stamp = rospy.Time.now()rospy.loginfo(robot_configuration)休息pub1.publish(robot_configuration)rospy.sleep(2)如果(选择 == 2):#rospy.Timer(rospy.Duration(2),joint_modifier)listen = rospy.Subscriber("joint_states", JointState, Joint_callback)rospy.spin()如果(选择 == 3):#rospy.Timer(rospy.Duration(2),joint_modifier)tactile_sub = rospy.Subscriber("/sr_tactile/touch/ff", Float64, tactile_callback)rospy.spin()

这就是我在程序主体内部调用节点的方式,

joint_modifier(2)打印(打印g_position")print(g_position)#查看g_position的格式打印(打印g _位置")leg_1 = Leg_attribute(g_position[0],g_position[1],g_position[2],velocity1 = 10,velocity2 = 10,velocity3 = 10,effort1 = 100,worker2 = 100,worker3 = 100,acceleration=1)

以这种方式调用时,程序卡在joint_modifier(2),因为该函数具有rospy.spin().

<预><代码>

解决方案

您使用的样式不是很标准.我假设您已经看过 example 在 ROS wiki 上,我对其进行了修改以演示下面的标准用法.

主要是解决您发布的代码,您需要使 listen 具有回调之外的全局范围.这是为了存储您想要的 data,而不是 Subscriber 对象.rospy.spin() 永远不会进入回调,只有主节点函数/部分.订阅者对象 listen1 很少使用,它不返回任何内容,也不存储它获取的数据.也就是说,您需要 Subscriber() 才能有一个非 None 回调.它更像是一个 bind,将 data 提供给 callback 而不是从 Subscriber 返回它.这就是为什么 listen1 (订阅者) 没有属性 position (联合状态).

导入rospy从 sensor_msgs.msg 导入 JointState# 订阅者#joint_sub (sensor_msgs/JointState): "joint_states"# 这是您存储收到的所有数据的地方g_joint_states = 无g_positions = 无g_pos1 = 无def timer_callback(event): # 输入rospy.TimerEventprint('timer_cb(' + str(event.current_real) + '): g_positions is')打印(str(None) 如果g_positions 是None else str(g_positions))def joint_callback(data): # JointState 类型的数据# 每个订阅者获得 1 个回调,并且回调要么# 存储信息和/或计算某些东西和/或发布# 它 _does not!_ 返回任何东西全局 g_joint_states、g_positions、g_pos1rospy.loginfo(data.position)g_joint_states = 数据g_positions = data.position如果 len(data.position) >0:g_pos1 = data.position[0]打印(g_positions)# 在你的主函数中,只有!你在这里订阅主题吗defjoint_logger_node():# 初始化 ROSrospy.init_node('joint_logger_node',anonymous=True)# 订阅者# 每个订阅者都有主题、主题类型和回调!rospy.Subscriber('joint_states', JointState, Joint_callback)# 很少需要使用变量来保持对象:#joint_sub = rospy.Subscriber(...)rospy.Timer(rospy.Duration(2), timer_callback)# spin() 只是让 python 不退出,直到该节点停止# 这是一个无限循环,唯一运行的代码是回调rospy.spin()# 在此之后没有代码,没有!使用定时器回调!# 除非你需要在程序终止时清理资源分配、close() 等如果 __name__ == '__main__':Joint_logger_node()

关于 Subscriber()、spin() 和 _callback(s) 的作用似乎有些混乱.在 Python 中有点模糊,但是有一个主程序来管理所有节点,并在它们之间发送节点.在每个节点中,我们向主程序注册该节点的存在,以及它有哪些发布者和订阅者.通过注册,这意味着我们告诉主程序,嘿,我想要那个话题!";在您的情况下,对于您的(未声明的)joint_sub 订阅者,嘿,我想要来自 joint_states 主题的所有 JointState 消息!"主程序每次(从某个地方的某个发布者处)获得一个新的 joint_states JointState msg 时,都会将其发送给该订阅者.订阅者通过回调处理、处理和处理味精(数据):当(!)我收到一条消息时,运行回调.

所以主程序从某个发布者那里收到一个新的joint_states JointState msg.然后它,因为我们注册了一个订阅者,将它发送到这个节点.rospy.spin() 是一个等待该数据的无限循环.这就是它的作用(主要是):

def rospy.spin():而 rospy.ok():对于来自 master() 的 get_new_messages 中的 new_msg:如果我有 new_msg 的订阅者:my_subscriber.callback(new_msg)

rospy.spin() 是您的回调、joint_callback(和/或 timer_callback 等)实际被调用和执行的地方.它在有数据时运行.

更根本的是,我认为由于这种混乱,您的程序结构存在缺陷;您的功能不会做您认为它们会做的事情.这就是你应该如何制作你的节点.

  1. 将您的数学部分(所有真正的非 ros 代码),即执行 NN 的部分,放入一个单独的模块中,并创建一个函数来运行它.
  2. 如果您只想在接收数据时运行它,请在回调中运行它.如果要发布结果,请在回调中发布.
  3. 不要调用主函数!if __init__ == '__main__': my_main_function() 应该是它被调用的唯一地方,这将调用你的代码.我再说一遍:声明subscribers/publishers/init/timers/parameters 的main 函数只在if __init__ ... 中运行,并且这个函数运行你的代码.要让它运行您的代码,请将您的代码放在回调中.计时器回调对此很方便.

我希望这个代码示例能够澄清:

导入rospy从 std_msgs.msg 导入标题从 sensor_msgs.msg 导入 JointState将 my_nn 导入为 nn # nn.run(data)# 订阅者#joint_sub (sensor_msgs/JointState): "joint_states"# 出版商#joint_pub (sensor_msgs/JointState): "target_joint_states"Joint_pub = 无def joint_callback(data): # JointState 类型的数据pub_msg = JointState() # 制作一个新的msg来发布结果pub_msg.header = Header()pub_msg.name = 数据.namepub_msg.velocity = [10] * len(data.name)pub_msg.effort = [100] * len(data.name)# 下一行可能不太适合您想要做的事情,# 但基本上,在数据上运行真实代码",并得到#要发布的结果pub_msg.position = nn.run(data.position) # 对数据运行NN,存储结果Joint_pub.publish(pub_msg) # 准备好后发送!如果 __name__ == '__main__':# 初始化 ROSrospy.init_node('joint_logger_node',anonymous=True)# 订阅者rospy.Subscriber('joint_states', JointState, Joint_callback)# 出版商Joint_pub = rospy.Publisher('target_joint_states', JointState, queue_size = 10)# 旋转rospy.spin()# 没有更多的代码!这不是要调用的函数,而是它的# 自己的程序!这是一个可执行文件!运行你的代码# 回调!

请注意,我们设计为 ros 节点的 python 模块没有可调用的函数.它具有定义的回调结构和它们之间共享的全局数据,所有这些都在 __init__ 中初始化和注册.

I have written a sample Subscriber. I want to feed the data that I have obtained from the rospy.Subscriber into another variable, so that I can use it later in the program for processing. At the moment I could see that the Subscriber is functioning as I can see the subscribed values being printed when I use rospy.loginfo() function. Although I donot know how to store this data into another varible. I have tried assigning it directly to a variable by using assignment operator '=', but I get error.

I have tried writing a callback function with rospy.loginfo to print the position data from the subscribed object. I have subscribed JointState and it containes, header, position, velocity and effort arrays. using rospy.loginfo I can verify that the subscriber is subscribing. But when i tried to assign it directly to a variable, I get an error.

I am displaying loginfo from a call back function as follows

def callback(data):
   rospy.loginfo(data.position)
   global listen
    listen = rospy.Subscriber("joint_states", JointState, 
    callback)
    rospy.spin()

and this works fine. But when i slightly modify the code to assign the subscribed values, I get following error i.e.

   listen1 = rospy.Subscriber("joint_states", JointState, 
   callback=None)
   listen = listen1.position
   #rospy.loginfo(listen)
   print(listen)
   rospy.spin()```

The error is as follows, 
 ```listen = listen1.position
    AttributeError: 'Subscriber' object has no attribute 'position'

EDIT: Here is my node I have defined in my program,

    #rospy.loginfo(msg.data)
    global tactile_states
    tactile_states = data.data

def joint_callback(data):
    #rospy.loginfo(data.position)
    global g_joint_states 
    global g_position
    global g_pos1
    g_joint_states = data
    #for i in len(data.position):
        #g_position[i] = data.position[i]
    g_position = data.position
    if len(data.position) > 0:
        print("jointstate more than 0")
        g_pos1 = data.position[0]
    #print(g_position)


def joint_modifier(*args):
    #choice describes what the node is supposed to do whether act as publisher or subscribe to joint states or tactile sensors
    rospy.init_node('joint_listener_publisher', anonymous=True)
    pub1 = rospy.Publisher('joint_states', JointState, queue_size = 10)
    if(len(args)>1):
        choice = args[0]
        joint_name = args[1]
        position = args[2]
    else:
        choice = args[0]
    if (choice == 1):
        rate = rospy.Rate(1)
        robot_configuration = JointState()
        robot_configuration.header = Header()
        robot_configuration.name = [joint_name]
        robot_configuration.position = [position]
        robot_configuration.velocity = [10]
        robot_configuration.effort = [100]
        while not rospy.is_shutdown():
            robot_configuration.header.stamp = rospy.Time.now()
            rospy.loginfo(robot_configuration)
            break
        pub1.publish(robot_configuration)
        rospy.sleep(2)
    if (choice == 2):
        #rospy.Timer(rospy.Duration(2), joint_modifier)
        listen = rospy.Subscriber("joint_states", JointState, joint_callback)
        rospy.spin()
    if (choice == 3):
        #rospy.Timer(rospy.Duration(2), joint_modifier)
        tactile_sub = rospy.Subscriber("/sr_tactile/touch/ff", Float64, tactile_callback)
        rospy.spin()

This is how I am calling the node inside the main body of the program,

           joint_modifier(2)
           print("printing g_position")
           print(g_position)#to check the format of g_position
           print("printed g _position")
           leg_1 = Leg_attribute(g_position[0], g_position[1], g_position[2], velocity1 = 10, velocity2 = 10, velocity3 = 10, effort1 = 100, effort2 = 100, effort3 = 100, acceleration=1)

When calling this way, the program is stuck at joint_modifier(2) as that function has rospy.spin().


解决方案

The style which you're using is not very standard. I assume you've seen the example on ROS wiki, I've modified it to demonstrate standard usage below.

Chiefly, addressing the code you posted, you needed to make listen have global scope outside of the callback. This is to store the data you want, not the Subscriber object. The rospy.spin() never goes in a callback, only the main node function/section. The subscriber object, listen1, which is used infrequently, doesn't return anything, and doesn't store the data it acquires. That is, you need Subscriber() to have a non-None callback. It's more of a bind, giving the data to the callback instead of returning it from Subscriber. That's why listen1 (Subscriber) has no attribute position (JointState).

import rospy
from sensor_msgs.msg import JointState

# Subscribers
#     joint_sub (sensor_msgs/JointState): "joint_states"

# This is where you store all your data you recieve
g_joint_states = None
g_positions = None
g_pos1 = None

def timer_callback(event): # Type rospy.TimerEvent
    print('timer_cb (' + str(event.current_real) + '): g_positions is')
    print(str(None) if g_positions is None else str(g_positions))

def joint_callback(data): # data of type JointState
    # Each subscriber gets 1 callback, and the callback either
    # stores information and/or computes something and/or publishes
    # It _does not!_ return anything
    global g_joint_states, g_positions, g_pos1
    rospy.loginfo(data.position)
    g_joint_states = data
    g_positions = data.position
    if len(data.position) > 0:
        g_pos1 = data.position[0]
    print(g_positions)

# In your main function, only! here do you subscribe to topics
def joint_logger_node():
    # Init ROS
    rospy.init_node('joint_logger_node', anonymous=True)

    # Subscribers
    # Each subscriber has the topic, topic type, AND the callback!
    rospy.Subscriber('joint_states', JointState, joint_callback)
    # Rarely need to hold onto the object with a variable: 
    #     joint_sub = rospy.Subscriber(...)
    rospy.Timer(rospy.Duration(2), timer_callback)

    # spin() simply keeps python from exiting until this node is stopped
    # This is an infinite loop, the only code that gets ran are callbacks
    rospy.spin()
    # NO CODE GOES AFTER THIS, NONE! USE TIMER CALLBACKS!
    # unless you need to clean up resource allocation, close(), etc when program dies

if __name__ == '__main__':
    joint_logger_node()

Edit 1: There seems to be some confusion on what Subscriber(), spin(), and _callback(s) do. It's a bit obscured in the Python, but there is a master program that manages all nodes, and sending nodes between them. In each node, we register with that master program that the node exists, and what publishers and subscribers it has. By register, it means we tell the master program, "Hey, I want that topic!"; in your case, for your (undeclared) joint_sub Subscriber, "Hey, I want all the JointState msgs from the joint_states topic!" The master program will, every time it gets (from some publisher somewhere) a new joint_states JointState msg, send it to that subscriber. The subscriber handles, deals with, and processes the msg (data) with a callback: when(!) I receive a message, run the callback.

So the master program receives a new joint_states JointState msg from some publisher. Then it, because we registered a subscriber to it, sends it to this node. rospy.spin() is an infinite loop waiting for that data. This is what it does (kinda-mostly):

def rospy.spin():
    while rospy.ok():
        for new_msg in get_new_messages from master():
            if I have a subscriber to new_msg:
                my_subscriber.callback(new_msg)

rospy.spin() is where your callback, joint_callback (and/or timer_callback, etc) actually get called, and executed. It only runs when there is data for it.

More fundamentally, I think because of this confusion, your program structure is flawed; your functions don't do what you think they do. This is how you should make your node.

  1. Make your math-portion (all the real non-ros code), the one doing the NN, into a separate module, and make a function to run it.
  2. If you only want to run it when you receive data, run it in the callback. If you want to publish the result, publish in the callback.
  3. Don't call the main function! The if __init__ == '__main__': my_main_function() should be the only place it gets called, and this will call your code. I repeat: the main function, declaring subscribers/publishers/init/timers/parameters, is only run in if __init__ ..., and this function runs your code. To have it run your code, place your code in a callback. Timer callbacks are handy for this.

I hope this code sample clarifies:

import rospy
from std_msgs.msg import Header
from sensor_msgs.msg import JointState
import my_nn as nn # nn.run(data)

# Subscribers
#     joint_sub (sensor_msgs/JointState): "joint_states"

# Publishers
#     joint_pub (sensor_msgs/JointState): "target_joint_states"

joint_pub = None

def joint_callback(data): # data of type JointState
    pub_msg = JointState() # Make a new msg to publish results
    pub_msg.header = Header()
    pub_msg.name = data.name
    pub_msg.velocity = [10] * len(data.name)
    pub_msg.effort = [100] * len(data.name)
    # This next line might not be quite right for what you want to do,
    # But basically, run the "real code" on the data, and get the
    # result to publish back out
    pub_msg.position = nn.run(data.position) # Run NN on data, store results
    joint_pub.publish(pub_msg) # Send it when ready!

if __name__ == '__main__':
    # Init ROS
    rospy.init_node('joint_logger_node', anonymous=True)
    # Subscribers
    rospy.Subscriber('joint_states', JointState, joint_callback)
    # Publishers
    joint_pub = rospy.Publisher('target_joint_states', JointState, queue_size = 10)
    # Spin
    rospy.spin()
    # No more code! This is not a function to call, but its
    # own program! This is an executable! Run your code in
    # a callback!

Notice that a python module we design to be a ros node, has no functions to be called. It has a defined structure of callbacks and global data shared between them, all initialized and registered in the __init__.

这篇关于如何将从 rospy.Subscriber 数据获得的数据提供给变量?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆