首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何将从rospy.Subscriber数据中获得的数据输入变量?

如何将从rospy.Subscriber数据中获得的数据输入变量?
EN

Stack Overflow用户
提问于 2019-07-30 11:56:39
回答 1查看 12K关注 0票数 6

我已经写了一个订户样本。我希望将从rospy.Subscriber获得的数据输入另一个变量,以便在以后的程序中使用它进行处理。目前,我可以看到订阅服务器正在运行,正如我在使用rospy.loginfo()函数时可以看到正在打印的订阅值一样。虽然我不知道如何将这些数据存储到另一个变量中。我尝试使用赋值运算符'=‘直接将它赋值给一个变量,但是我得到了错误。

我尝试用rospy.loginfo编写一个回调函数,以便从订阅对象中打印位置数据。我订阅了JointState,它包含了,标题,位置,速度和努力数组。使用rospy.loginfo,我可以验证订阅者是否订阅。但是当我试图将它直接赋值给一个变量时,我会得到一个错误。

我从回调函数中显示loginfo,如下所示

代码语言:javascript
复制
def callback(data):
   rospy.loginfo(data.position)
   global listen
    listen = rospy.Subscriber("joint_states", JointState, 
    callback)
    rospy.spin()

这个很好用。但是,当我稍微修改代码以分配订阅的值时,我会得到以下错误:

代码语言:javascript
复制
   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'

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

代码语言:javascript
复制
    #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()

这就是我如何调用程序主体内的节点,

代码语言:javascript
复制
           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)

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

代码语言:javascript
复制
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2019-07-30 18:17:07

你所使用的风格不是很标准。我想您已经在ROS上看到了示例,我已经对它进行了修改,以演示下面的标准用法。

主要是,对您发布的代码进行寻址,您需要使listen具有回调之外的全局范围。这是为了存储您想要的data,而不是订阅服务器对象。rospy.spin()从不进入回调,只有主节点函数/节。订阅服务器对象listen1不经常使用,不返回任何内容,也不存储它获取的数据。也就是说,需要订户()才能进行非无回调。它更像是一个bind,将data交给callback而不是从订阅服务器返回。这就是为什么listen1 (订户)没有属性position (JointState)的原因。

代码语言:javascript
复制
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()

编辑1:对于订户()、spin()和_callback做什么似乎有些混淆。它在Python中有点模糊,但是有一个主程序管理所有节点,并在它们之间发送节点。在每个节点中,我们向该节点存在的主程序注册,以及它有哪些发布者和订阅者。注册意味着我们告诉主程序,“嘿,我想要那个主题!”;在您的例子中,对于您(未声明的) joint_sub订阅者来说,“嘿,我想要来自joint_states主题的所有JointState消息!”主程序每次(从某个出版商那里)获得一个新的joint_states JointState msg时,都会将它发送给该订阅服务器。订阅者使用回调来处理、处理和处理msg (数据):The (!)我收到一条消息,打电话回来。

因此,主程序从某个发布者接收一个新的joint_states JointState msg。然后,因为我们向它注册了一个订阅者,所以它将它发送到这个节点。rospy.spin()是一个等待该数据的无限循环。这就是它所做的(有点-大部分):

代码语言:javascript
复制
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()是调用和执行回调、joint_callback (和/或timer_callback等)的地方。只有当有数据时,它才会运行。

更根本的是,我认为由于这种混乱,您的程序结构是有缺陷的;您的功能不像您认为的那样。这就是您应该如何使您的节点。

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

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

代码语言:javascript
复制
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!

注意,我们设计的python模块是一个ros节点,没有函数可调用。它有一个在它们之间共享的回调和全局数据的定义结构,所有这些都初始化并在主函数/ if __name__ == '__main__'中注册。

票数 4
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/57271100

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档