ROS 安装及话题、服务、动作基本概念介绍

一、引言

机器人操作系统(ROS)是一个广泛应用于机器人开发的开源框架,它提供了丰富的工具和库,使得机器人开发者能够更高效地构建复杂的机器人应用。本文将详细介绍 ROS 的安装过程,并深入解析 ROS 中话题(Topic)、服务(Service)、动作(Action)这三个基本概念。

二、ROS 安装

(一)环境准备

在安装 ROS 之前,需要确保你的系统满足一定的条件。通常,ROS 支持多种 Linux 发行版,如 Ubuntu 等。以在 Ubuntu 系统上安装为例,首先要保证系统已经连接到互联网,并且具有管理员权限。

(二)添加软件源

打开终端,通过以下命令添加 ROS 的软件源:

sudo sh -c 'echo "deb http://packages.ros.org/ros/ubuntu $(lsb_release -sc) main" > /etc/apt/sources.list.d/ros-latest.list'

这个命令的作用是将 ROS 官方软件源的地址写入到系统的软件源列表文件中,以便后续能够从该源下载 ROS 相关的软件包。

(三)设置密钥

为了确保软件包的完整性和安全性,需要添加 ROS 官方的 GPG 密钥:

sudo apt-key adv --keyserver 'hkp://keyserver.ubuntu.com:80' --recv-key C1CF6E31E6BADE8868B172B4F42ED6FBAB17C654

该命令从指定的密钥服务器获取 ROS 官方的 GPG 密钥,并将其添加到系统的密钥环中。

(四)更新软件包列表

执行以下命令更新系统的软件包列表,让系统获取到刚刚添加的 ROS 软件源中的软件包信息:

sudo apt update

(五)安装 ROS

根据你的需求选择不同的 ROS 安装版本,常见的有桌面完整版、桌面版和基础版等。以安装桌面完整版为例,执行以下命令:

sudo apt install ros - melodic - desktop - full

这里的melodic是 ROS 的版本号,你可以根据实际情况进行替换。安装过程可能需要一些时间,系统会自动下载并安装 ROS 及其相关的依赖包。

(六)初始化 rosdep

rosdep 是 ROS 中的一个重要工具,用于管理 ROS 软件包的依赖项。安装完成后,需要对 rosdep 进行初始化:

sudo rosdep init
rosdep update

第一条命令初始化 rosdep,第二条命令更新 rosdep 的依赖数据库。

(七)设置环境变量

为了让系统能够正确识别 ROS 的命令和工具,需要设置 ROS 的环境变量。在终端中执行以下命令:

echo "source /opt/ros/melodic/setup.bash" >> ~/.bashrc
source ~/.bashrc

第一条命令将 ROS 的环境变量设置命令写入到用户的.bashrc文件中,这样每次打开终端时都会自动执行该命令。第二条命令立即执行该设置,使当前终端会话生效。

三、话题(Topic)

(一)概念

话题是 ROS 中节点之间进行异步通信的主要方式。可以将话题想象成一个公共的消息通道,不同的节点可以向这个通道发布消息,也可以从这个通道订阅消息。例如,在一个机器人导航系统中,激光雷达节点可以向 “/scan” 话题发布激光扫描数据,而导航节点则可以订阅 “/scan” 话题,获取这些数据来进行路径规划。

(二)特点

  1. 异步通信:发布者和订阅者之间不需要知道对方的存在,它们只关注话题。发布者只管将消息发布到话题上,而订阅者只管从话题上接收消息。这种异步机制使得系统的耦合度降低,各个节点可以独立开发和运行。
  1. 一对多或多对多:一个话题可以有多个发布者和多个订阅者。例如,多个传感器节点可以同时向一个话题发布数据,而多个处理节点也可以同时订阅这个话题的数据。

(三)示例代码

在 Python 中,使用 ROS 的 rospy 库创建一个简单的话题发布者和订阅者。

  1. 发布者代码
#!/usr/bin/env python
import rospy
from std_msgs.msg import String

def talker():
    pub = rospy.Publisher('chatter', String, queue_size = 10)
    rospy.init_node('talker', anonymous = True)
    rate = rospy.Rate(10) # 10hz
    while not rospy.is_shutdown():
        hello_str = "hello world %s" % rospy.get_time()
        rospy.loginfo(hello_str)
        pub.publish(hello_str)
        rate.sleep()

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

在这段代码中,首先创建了一个Publisher对象,指定了话题名称为 “chatter”,消息类型为String,队列大小为 10。然后初始化 ROS 节点,设置发布频率为 10Hz。在循环中,不断生成消息并发布到话题上。

2. 订阅者代码

 
#!/usr/bin/env python
import rospy
from std_msgs.msg import String

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

def listener():
    rospy.init_node('listener', anonymous = True)
    rospy.Subscriber("chatter", String, callback)
    rospy.spin()

if __name__ == '__main__':
    listener()

这段代码中,创建了一个Subscriber对象,订阅了 “chatter” 话题,当有新消息到达时,会调用callback函数进行处理。

四、服务(Service)

(一)概念

服务是一种节点间的同步通信方式。与话题不同,服务是基于请求 - 响应模型的。一个节点(客户端)向另一个节点(服务端)发送请求,服务端接收到请求后进行处理,并返回响应给客户端。例如,在机器人抓取物体的场景中,抓取控制节点可以作为客户端,向物体识别节点(服务端)发送获取物体位置的请求,物体识别节点处理请求后,将物体的位置信息作为响应返回给抓取控制节点。

(二)特点

  1. 同步通信:客户端发送请求后,会等待服务端的响应,直到收到响应后才会继续执行后续的代码。这种同步机制适用于需要立即得到结果的场景。
  1. 一对一:一个服务请求对应一个服务响应,且通常是一对一的关系,即一个客户端对应一个服务端。

(三)示例代码

同样以 Python 为例,创建一个简单的服务客户端和服务端。

  1. 服务端代码
#!/usr/bin/env python
import rospy
from beginner_tutorials.srv import AddTwoInts, AddTwoIntsResponse

def handle_add_two_ints(req):
    rospy.loginfo("Returning [%s + %s = %s]", req.a, req.b, (req.a + req.b))
    return AddTwoIntsResponse(req.a + req.b)

def add_two_ints_server():
    rospy.init_node('add_two_ints_server')
    s = rospy.Service('add_two_ints', AddTwoInts, handle_add_two_ints)
    rospy.loginfo("Ready to add two ints.")
    rospy.spin()

if __name__ == '__main__':
    add_two_ints_server()

在这段代码中,定义了一个服务处理函数handle_add_two_ints,它接收一个请求对象req,并返回一个响应对象。然后创建了一个服务,指定服务名称为 “add_two_ints”,服务类型为AddTwoInts,并将服务处理函数与服务关联起来。

2. 客户端代码

#!/usr/bin/env python
import sys
import rospy
from beginner_tutorials.srv import AddTwoInts

def add_two_ints_client(x, y):
    rospy.wait_for_service('add_two_ints')
    try:
        add_two_ints = rospy.ServiceProxy('add_two_ints', AddTwoInts)
        resp1 = add_two_ints(x, y)
        return resp1.sum
    except rospy.ServiceException as e:
        rospy.loginfo("Service call failed: %s", e)

def usage():
    return "%s [x y]" % sys.argv[0]

if __name__ == "__main__":
    if len(sys.argv) == 3:
        x = int(sys.argv[1])
        y = int(sys.argv[2])
    else:
        print(usage())
        sys.exit(1)
    rospy.loginfo("Requesting %s+%s", x, y)
    print("Sum is %s" % (add_two_ints_client(x, y)))

客户端代码中,首先等待 “add_two_ints” 服务可用,然后创建一个服务代理对象add_two_ints,通过该对象向服务端发送请求,并获取响应结果。

五、动作(Action)

(一)概念

动作是一种介于话题和服务之间的通信方式,适用于处理耗时较长且需要反馈的任务。它允许客户端向服务端发送目标请求,服务端在执行任务的过程中,可以向客户端反馈任务的执行进度,任务完成后还可以返回最终的结果。例如,在机器人的导航任务中,客户端可以向导航动作服务器发送一个目标位置,导航动作服务器在导航过程中,可以不断向客户端反馈当前的位置、剩余距离等信息,当到达目标位置后,再返回最终的导航结果。

(二)特点

  1. 支持反馈:与服务不同,动作不仅可以返回最终结果,还能在执行过程中不断提供反馈信息,让客户端实时了解任务的进展情况。
  1. 可取消:客户端可以在任务执行过程中随时取消目标请求,这在一些需要灵活控制的场景中非常有用。

(三)示例代码

以 ROS 的 actionlib 库为例,创建一个简单的动作客户端和动作服务器。

  1. 动作服务器代码
#!/usr/bin/env python
import rospy
import actionlib
from beginner_tutorials.msg import FibonacciAction, FibonacciFeedback, FibonacciResult

def fibonacci(n):
    if n == 0:
        return 0
    elif n == 1:
        return 1
    else:
        return fibonacci(n - 1) + fibonacci(n - 2)

def execute_cb(goal):
    r = rospy.Rate(1)
    success = True
    feedback = FibonacciFeedback()
    result = FibonacciResult()
    feedback.sequence = []
    for i in range(1, goal.order + 1):
        if server.is_preempt_requested():
            rospy.loginfo('The goal has been cancelled/preempted')
            server.set_preempted()
            success = False
            break
        feedback.sequence.append(fibonacci(i))
        server.publish_feedback(feedback)
        r.sleep()
    if success:
        result.sequence = feedback.sequence
        rospy.loginfo('Succeeded calculating Fibonacci of order %d', goal.order)
        server.set_succeeded(result)

rospy.init_node('fibonacci_server')
server = actionlib.SimpleActionServer('fibonacci', FibonacciAction, execute_cb, False)
server.start()
rospy.loginfo('The Fibonacci server is ready to receive goals')
rospy.spin()

在这段代码中,定义了一个计算斐波那契数列的函数fibonacci。在execute_cb函数中,根据客户端发送的目标(计算斐波那契数列的阶数),在循环中计算数列,并通过publish_feedback方法向客户端发送反馈信息。如果任务被取消,会进行相应的处理。任务完成后,设置服务成功并返回结果。

2. 动作客户端代码

#!/usr/bin/env python
import rospy
import actionlib
from beginner_tutorials.msg import FibonacciAction, FibonacciGoal

def feedback_cb(feedback):
    rospy.loginfo('Received feedback: %s', feedback.sequence)

rospy.init_node('fibonacci_client')
client = actionlib.SimpleActionClient('fibonacci', FibonacciAction)
rospy.loginfo('Waiting for action server to start')
client.wait_for_server()
goal = FibonacciGoal()
goal.order = 20
rospy.loginfo('Sending goal: %d', goal.order)
client.send_goal(goal, feedback_cb = feedback_cb)
client.wait_for_result()
rospy.loginfo('Result: %s', client.get_result())

客户端代码中,创建了一个动作客户端对象client,等待动作服务器启动。然后设置目标(计算 20 阶的斐波那契数列),通过send_goal方法向服务器发送目标,并设置反馈回调函数feedback_cb。最后等待任务完成并获取结果。

六、总结

ROS 中的话题、服务和动作是其核心的通信机制,它们各自适用于不同的场景。话题用于异步的、一对多或多对多的消息传递;服务用于同步的、一对一的请求 - 响应通信;动作则适用于处理耗时较长且需要反馈和可取消的任务。在实际的机器人开发中,合理运用这三种通信机制,可以构建出高效、灵活的机器人系统。通过本文对 ROS 安装以及这三个基本概念的介绍,希望能够帮助读者更好地理解和使用 ROS 进行机器人开发。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值