ROS常用API(1)
def init_node(name, argv=None, anonymous=False, log_level=None, disable_rostime=False, disable_rosout=False, disable_signals=False, xmlrpc_port=0, tcpros_port=0):
"""
在ROS msater中注册节点
@param name: 节点名称,必须保证节点名称唯一,节点名称中不能使用命名空间(不能包含 '/')
@type name: str
@param anonymous: 取值为 true 时,为节点名称后缀随机编号
@type anonymous: bool
"""
ROS初始化
name—设置节点名称
argv=None—封装节点调用时传递的参数
anonymous=False—可以为节点名称生成随机后缀,可以解决重名问题
class Publisher(Topic):
"""
在ROS master注册为相关话题的发布方
"""
def __init__(self, name, data_class, subscriber_listener=None, tcp_nodelay=False, latch=False, headers=None, queue_size=None):
"""
Constructor
@param name: 话题名称
@type name: str
@param data_class: 消息类型
@param latch: 如果为 true,该话题发布的最后一条消息将被保存,并且后期当有订阅者连接时会将该消息发送给订阅者
@type latch: bool
@param queue_size: 等待发送给订阅者的最大消息数量
@type queue_size: int
"""
Function:如果为 true,该话题发布的最后一条消息将被保存,并且后期当有订阅者连接时会将该消息发送给订阅者
Using:latch = True
notice:可以保存数据,例如保存静态地图,当有订阅时发送即可,不用一直循环发布。
def publish(self, *args, **kwds):
"""
发布消息
"""
class Subscriber(Topic):
"""
类注册为指定主题的订阅者,其中消息是给定类型的。
"""
def __init__(self, name, data_class, callback=None, callback_args=None,
queue_size=None, buff_size=DEFAULT_BUFF_SIZE, tcp_nodelay=False):
"""
Constructor.
@param name: 话题名称
@type name: str
@param data_class: 消息类型
@type data_class: L{Message} class
@param callback: 处理订阅到的消息的回调函数
@type callback: fn(msg, cb_args)
@param queue_size: 消息队列长度,超出长度时,头部的消息将被弃用
"""
class Service(ServiceImpl):
"""
声明一个ROS服务
使用示例::
s = Service('getmapservice', GetMap, get_map_handler)
"""
def __init__(self, name, service_class, handler,
buff_size=DEFAULT_BUFF_SIZE, error_handler=None):
"""
@param name: 服务主题名称 ``str``
@param service_class:服务消息类型
@param handler: 回调函数,处理请求数据,并返回响应数据
@type handler: fn(req)->resp
"""
class ServiceProxy(_Service):
"""
创建一个ROS服务的句柄
示例用法::
add_two_ints = ServiceProxy('add_two_ints', AddTwoInts)
resp = add_two_ints(1, 2)
"""
def __init__(self, name, service_class, persistent=False, headers=None):
"""
ctor.
@param name: 服务主题名称
@type name: str
@param service_class: 服务消息类型
@type service_class: Service class
"""
def call(self, *args, **kwds):
"""
发送请求,返回值为响应数据
"""
def wait_for_service(service, timeout=None):
"""
调用该函数时,程序会处于阻塞状态直到服务可用
@param service: 被等待的服务话题名称
@type service: str
@param timeout: 超时时间
@type timeout: double|rospy.Duration
"""
rospy.spin()
Question:rospy.spin是如何知道rospy.Subscriber中的回调函数的?
Answers:在ROS中,rospy.spin()
通过 ROS Master 进行通信,了解当前节点的订阅者(Subscribers)以及它们注册的回调函数。当节点订阅一个主题时,它向ROS Master注册自己对该主题的订阅,并提供一个回调函数。ROS Master 将这些信息保存,并在主题有新消息到达时通知订阅者的节点。
具体来说,当你使用 rospy.Subscriber("jiaoSheTou", Person, doPerson)
创建一个订阅者时:
节点注册订阅者: 你的ROS节点向ROS Master注册了对 “jiaoSheTou” 主题的订阅,并指定了回调函数 doPerson
。
ROS Master保存信息: ROS Master 接收到节点的注册信息,保存了节点对 “jiaoSheTou” 主题的订阅以及相应的回调函数。
消息到达: 当 “jiaoSheTou” 主题有新的消息到达时,ROS Master会通知你的节点,告知有新的数据可用。
回调函数执行: 在 rospy.spin()
的循环中,节点检测到有新消息到达 “jiaoSheTou” 主题,于是调用之前注册的回调函数 doPerson
,并将接收到的消息作为参数传递给该函数。
总体来说,rospy.spin()
并不直接知道 rospy.Subscriber
中的回调函数。相反,ROS Master 起到了中介的角色,协调和管理各个节点的订阅和发布,以确保在有新消息到达时正确调用相应的回调函数。
获取时刻,或者设置指定时刻
# 获取当前时刻
right_now = rospy.Time.now()
rospy.loginfo("当前时刻:%.2f",right_now.to_sec())
rospy.loginfo("当前时刻:%.2f",right_now.to_nsec())
# 自定义时刻
# Time(secs=0, nsecs=0)
some_time1 = rospy.Time(1234.567891011)
some_time2 = rospy.Time(1234,567891011)
rospy.loginfo("设置时刻1:%.2f",some_time1.to_sec())
rospy.loginfo("设置时刻2:%.2f",some_time2.to_sec())
# 从时间创建对象
# some_time3 = rospy.Time.from_seconds(543.21)
some_time3 = rospy.Time.from_sec(543.21) # from_sec 替换了 from_seconds
rospy.loginfo("设置时刻3:%.2f",some_time3.to_sec())
设置一个时间区间(间隔)
# 持续时间相关API
rospy.loginfo("持续时间测试开始.....")
du = rospy.Duration(3.3)
rospy.loginfo("du1 持续时间:%.2f",du.to_sec())
rospy.sleep(du) #休眠函数
rospy.loginfo("持续时间测试结束.....")
在你提供的代码中,rospy.Duration(3.3)
创建了一个 rospy.Duration
对象,表示持续时间为3.3秒。然后通过 rospy.sleep(du)
使用这个持续时间进行休眠。
相比于直接使用 rospy.sleep(3.3)
,使用 rospy.Duration
对象的主要优势在于更加灵活。rospy.Duration
允许你以秒和纳秒为单位指定持续时间,而 rospy.sleep()
的参数是一个浮点数,表示以秒为单位的休眠时间。
例如,你可以使用 rospy.Duration
表示更精确的时间,如3.333 秒:
du = rospy.Duration.from_sec(3.333)
rospy.sleep(du)
这种方式允许你以更细粒度的时间单位指定休眠时间。在一些需要更精确等待的情况下,使用 rospy.Duration
可以提供更灵活的控制。
为了方便使用,ROS中提供了时间与时刻的运算:
rospy.loginfo("时间运算")
now = rospy.Time.now()
du1 = rospy.Duration(10)
du2 = rospy.Duration(20)
rospy.loginfo("当前时刻:%.2f",now.to_sec())
before_now = now - du1
after_now = now + du1
dd = du1 + du2
# now = now + now #非法
rospy.loginfo("之前时刻:%.2f",before_now.to_sec())
rospy.loginfo("之后时刻:%.2f",after_now.to_sec())
rospy.loginfo("持续时间相加:%.2f",dd.to_sec())
在ROS中,rospy.Time
是不可变(immutable)的对象,这意味着一旦创建,就无法通过直接修改现有的 rospy.Time
对象来更改其值。在你的代码中,now
的值是通过 rospy.Time.now()
获取的,这个值在创建后是不可变的。
因此,下面这行代码是非法的,会导致运行时错误:
# now = now + now # 非法
这是因为 now + now
尝试创建一个新的 rospy.Time
对象,其值等于两个现有对象的和,但由于 rospy.Time
是不可变的,无法直接修改现有对象的值。
但是,你可以通过其他方式进行时间的修改和运算,例如创建新的 rospy.Time
对象来表示过去或未来的时间点,或者使用 rospy.Duration
对象来表示时间间隔。在你的代码中,before_now
和 after_now
就是通过 rospy.Duration
对象进行时间运算得到的。
总的来说,rospy.Time
对象是不可变的,但你可以通过其他对象(如 rospy.Duration
)进行时间的计算和操作。