2.1 創建 ROS 功能包

ROS(Robot Operating System)是一種開源的機器人軟件框架,廣泛用於機器人開發中。通過使用 ROS,開發者可以輕鬆創建和管理機器人應用程序。在本節中,我們將介紹如何創建一個 ROS 功能包並實現一些基本功能。

2.1.1 使用 ROS 主題

ROS 主題(Topic)是一種發佈/訂閲機制,允許節點之間進行通信。每個節點可以發佈主題消息或訂閲主題消息來獲取數據。以下是如何使用 ROS 主題的步驟:

創建功能包

首先,我們需要創建一個新的 ROS 功能包。在終端中運行以下命令:

catkin_create_pkg de_ws my_robot rospy roscpp

ROS 編程入門的介紹_xml

此命令創建一個名為 my_robot 的功能包,並聲明瞭對 std_msgsrospyroscpp 的依賴。

創建發佈者節點

接下來,我們在功能包中創建一個發佈者節點。新建一個名為 talker.py 的文件,並添加以下內容:

#!/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

此代碼定義了一個發佈者節點 talker,它每秒鐘發佈一條 "hello world" 消息到主題 chatter

2.1.2 創建 ROS 節點

ROS 節點是 ROS 系統中的基本執行單元。每個節點可以執行一個任務,如傳感器數據處理、運動控制等。下面我們創建一個訂閲者節點來接收 talker 節點發布的消息。

創建訂閲者節點

新建一個名為 listener.py 的文件,並添加以下內容:

ROS 編程入門的介紹_客户端_02

#!/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()

此代碼定義了一個訂閲者節點 listener,它接收主題 chatter 上的消息並打印出來。

2.1.3 編譯節點

在我們運行節點之前,需要編譯功能包。確保在功能包的 CMakeLists.txtpackage.xml 文件中正確配置了依賴項。然後在終端中運行以下命令:

cd ~/catkin_ws
catkin_make

編譯完成後,可以運行節點:

roscore
rosrun my_robot talker.py
rosrun my_robot listener.py

此時,你應該可以看到 listener 節點打印出 talker 節點發布的消息。

ROS 編程入門的介紹_客户端_03

添加自定義的 .msg 文件和 .srv 文件

在 ROS 中,自定義消息類型和服務類型是很常見的需求。我們可以定義自己的消息和服務文件來滿足特定的應用需求。

創建自定義 .msg 文件

首先,在 my_robot 功能包的 msg 目錄下創建一個新的消息文件,例如 CustomMessage.msg

string content
int32 number

然後,在 CMakeLists.txt 文件中添加以下內容:

add_message_files(
  FILES
  CustomMessage.msg
)

package.xml 文件中添加依賴:

<build_depend>message_generation</build_depend>
<exec_depend>message_runtime</exec_depend>

最後,重新編譯功能包:

catkin_make

創建自定義 .srv 文件

類似地,我們可以在 srv 目錄下創建一個新的服務文件,例如 CustomService.srv

string request
---
string response

然後,在 CMakeLists.txt 文件中添加以下內容:

add_service_files(
  FILES
  CustomService.srv
)

package.xml 文件中添加依賴:

<build_depend>message_generation</build_depend>
<exec_depend>message_runtime</exec_depend>

重新編譯功能包:

catkin_make

2.3 使用 ROS 服務

ROS 服務是一種請求/響應機制,允許節點之間進行同步通信。

2.3.1 使用 ROS actionlib

actionlib 是 ROS 中用於處理長時間運行任務的庫。它提供了一種客户端-服務器架構,允許客户端請求服務器執行某些任務,並在任務完成時收到通知。

創建動作服務器

my_robot 功能包中創建一個新的 Python 文件 action_server.py

ROS 編程入門的介紹_xml_04

ROS 編程入門的介紹_服務器_05

#!/usr/bin/env python

import rospy
import actionlib
from my_robot.msg import CustomAction, CustomActionFeedback, CustomActionResult

class CustomActionServer(object):
    _feedback = CustomActionFeedback()
    _result = CustomActionResult()

    def __init__(self):
        self._as = actionlib.SimpleActionServer("custom_action", CustomAction, self.execute_cb, False)
        self._as.start()

    def execute_cb(self, goal):
        rospy.loginfo('Executing goal: %s', goal)
        success = True

        for i in range(1, goal.order):
            if self._as.is_preempt_requested():
                rospy.loginfo('Goal preempted')
                self._as.set_preempted()
                success = False
                break
            self._feedback.sequence = i
            self._as.publish_feedback(self._feedback)
            rospy.sleep(1.0)

        if success:
            self._result.sequence = goal.order
            self._as.set_succeeded(self._result)

if __name__ == '__main__':
    rospy.init_node('custom_action_server')
    server = CustomActionServer()
    rospy.spin()

創建動作客户端

在 my_robot 功能包中創建一個新的 Python 文件 action_client.py:

#!/usr/bin/env python

import rospy
import actionlib
from my_robot.msg import CustomAction, CustomActionGoal

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

if __name__ == '__main__':
    rospy.init_node('custom_action_client')
    client = actionlib.SimpleActionClient('custom_action', CustomAction)
    client.wait_for_server()

    goal = CustomActionGoal()
    goal.order = 10

    client.send_goal(goal, feedback_cb=feedback_cb)
    client.wait_for_result()
    rospy.loginfo('Result: %s', client.get_result())

2.3.2 編譯 ROS 動作服務器和客户端

在編譯功能包之前,確保在 CMakeLists.txtpackage.xml 中添加了對 actionlib 和自定義消息的依賴。

然後在終端中運行以下命令:

catkin_make

啓動動作服務器和客户端:

rosrun my_robot action_server.py
rosrun my_robot action_client.py

2.4 創建啓動文件

啓動文件用於同時啓動多個 ROS 節點,簡化了複雜系統的啓動過程。

創建一個新的啓動文件 my_robot.launch

<launch>
  <node pkg="my_robot" type="talker.py" name="talker" output="screen"/>
  <node pkg="my_robot" type="listener.py" name="listener" output="screen"/>
</launch>

運行啓動文件:

roslaunch my_robot my_robot.launch

2.5 主題、服務和 actionlib 的應用

在實際應用中,主題、服務和 actionlib 可以結合使用,實現複雜的機器人行為。例如,一個機器人可以通過主題獲取傳感器數據,通過服務進行路徑規劃,通過 actionlib 執行長時間的導航任務。

以下是一個綜合應用示例:

  • 主題用於發佈傳感器數據。
  • 服務用於路徑規劃。
  • actionlib 用於執行導航任務。

2.6 總結

本文介紹瞭如何創建 ROS 功能包,並使用主題、服務和 actionlib 實現機器人功能。通過這些基礎知識,您可以構建複雜的機器人應用程序。

2.7 問題

在學習和使用 ROS 的過程中,可能會遇到以下問題:

  • 功能包無法編譯:檢查依賴是否正確添加。
  • 節點無法通信:確保主題和服務名稱一致。
  • 動作服務器和客户端無法連接:檢查 actionlib 配置是否正確。