ROS常用API(1)

发布时间:2024年01月19日

ROS常用API(1)

初始化

ros.init_node()

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
   """
Function

ROS初始化

Parameter

name—设置节点名称
argv=None—封装节点调用时传递的参数
anonymous=False—可以为节点名称生成随机后缀,可以解决重名问题

Use
  1. argv using:可以按照ROS中指定的语法格式传递参数,ROS可以解析并加以使用
  2. anonymous using

话题与服务相关对象

1. 发布对象

对象获取

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

        """

latch

Function:如果为 true,该话题发布的最后一条消息将被保存,并且后期当有订阅者连接时会将该消息发送给订阅者
Using:latch = True
notice:可以保存数据,例如保存静态地图,当有订阅时发送即可,不用一直循环发布。

消息发布函数

def publish(self, *args, **kwds):
        """
        发布消息
        """

2.发布对象

对象获取

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: 消息队列长度,超出长度时,头部的消息将被弃用

        """

3.服务对象

对象获取

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

        """

4.客户端对象

对象获取

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) 创建一个订阅者时:

  1. 节点注册订阅者: 你的ROS节点向ROS Master注册了对 “jiaoSheTou” 主题的订阅,并指定了回调函数 doPerson

  2. ROS Master保存信息: ROS Master 接收到节点的注册信息,保存了节点对 “jiaoSheTou” 主题的订阅以及相应的回调函数。

  3. 消息到达: 当 “jiaoSheTou” 主题有新的消息到达时,ROS Master会通知你的节点,告知有新的数据可用。

  4. 回调函数执行:rospy.spin() 的循环中,节点检测到有新消息到达 “jiaoSheTou” 主题,于是调用之前注册的回调函数 doPerson,并将接收到的消息作为参数传递给该函数。

总体来说,rospy.spin() 并不直接知道 rospy.Subscriber 中的回调函数。相反,ROS Master 起到了中介的角色,协调和管理各个节点的订阅和发布,以确保在有新消息到达时正确调用相应的回调函数。

时间

1.时刻

获取时刻,或者设置指定时刻

# 获取当前时刻
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())

2.持续时间

设置一个时间区间(间隔)

# 持续时间相关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 可以提供更灵活的控制。

3.持续时间与时刻运算

为了方便使用,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())

notice

在ROS中,rospy.Time 是不可变(immutable)的对象,这意味着一旦创建,就无法通过直接修改现有的 rospy.Time 对象来更改其值。在你的代码中,now 的值是通过 rospy.Time.now() 获取的,这个值在创建后是不可变的。

因此,下面这行代码是非法的,会导致运行时错误:

# now = now + now  # 非法

这是因为 now + now 尝试创建一个新的 rospy.Time 对象,其值等于两个现有对象的和,但由于 rospy.Time 是不可变的,无法直接修改现有对象的值。

但是,你可以通过其他方式进行时间的修改和运算,例如创建新的 rospy.Time 对象来表示过去或未来的时间点,或者使用 rospy.Duration 对象来表示时间间隔。在你的代码中,before_nowafter_now 就是通过 rospy.Duration 对象进行时间运算得到的。

总的来说,rospy.Time 对象是不可变的,但你可以通过其他对象(如 rospy.Duration)进行时间的计算和操作。

文章来源:https://blog.csdn.net/2302_79853609/article/details/135663917
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。