# 機器人作業系統能幫我寫作業嗎?ROS 2 究竟是何方神聖 Copyright (c) 2025 NCKU sspfr [section - 2](/0heMGItdRMmcdKViZ7po1Q) ## 前言 作業系統是個相對於直接的硬、軟體比較抽象的一個概念。 舉個例子來講,你今天買了一些電腦零件,好比 cpu、記憶體、主機板等等,開開心心回家組了台電腦,組完後颯爽的按下開機。螢幕除了輸出個 bios 啥都沒有,你還以為自己得了 MVP,結果現在連遊戲都不知道哪裡下載。頓時你想起了 windows 這個作業系統,只要安裝後鍵盤、滑鼠就可以做相對應的輸入,並且控制其他零件例如圖像的輸出、聲音的播放。作業系統即做了一個硬體-硬體間、硬體-軟體間,重要橋樑的工作。 回到機器人,假設你想組台會自己辨識路況的自駕車,你需要哪些零組件?會動要有馬達、馬達會動要有電池、辨識路況要有 sensor、運算 sensor 的回傳資料再決定車要往哪開要有軟體。這些東西加起來要你用 `c / c++` 寫一套韌體自己驅動應該會想死吧!這時候 ROS 就登場了,其可作為良好的橋樑,幫助我們更方便的做硬、軟體間的交互溝通。 ## ROS 簡介 ![image](https://hackmd.io/_uploads/S1tdZOCTJl.png) ROS 全名 Robot Operating System,顧名思義是類似給機器人使用的作業系統,但此作業系統非彼傳統意義上的作業系統,更像是一套中介軟體,幫助開發者更容易的去建構複雜且強大的機器人軟體。 其開源易上手的特性吸引了不止各大企業使用,亦有不少個人、小團體的開發團隊使用其作為控制自動化、機器人的核心框架。 ## ROS 的主要特色 ### 模組化架構 ROS 採用節點(Node)架構,把多種功能拆分成一個一個的節點,方便編輯以及後續維護。 ![image](https://hackmd.io/_uploads/S1uNc_06yl.png) > 圖片出處:[The Robotics Backend](https://roboticsbackend.com/what-is-ros/) ### 通訊機制 提供發佈 / 訂閱(Publish / Subscribe)、服務(Service)和動作(Action)等通訊模式,讓各個節點之間能夠有效協作。 ### 與硬體搭配 ROS 能夠與多種感測器與執行器整合,讓開發者不必從 kernal 開始編寫。 ## ROS 1 和 ROS 2 的區別 ![image](https://hackmd.io/_uploads/ByS9xq061l.png) > 圖片出處:[Research Gate](https://www.researchgate.net/figure/ROS1-ROS2-architecture-for-DDS-approach-to-ROS-We-clarify-the-performance-of-the-data_fig1_309128426) ### 節點通訊 如上圖可見,ROS 1 在節點的管理上還需額外設置 ROS Master,ROS 2 則改用 DDS(Data Distribution Servivce) 作為通訊介面,在節點的設定上較為容易,亦在資料的傳輸上更為安全。 ### 多系統支援 ROS 1 僅可在 linux 中運行,而 ROS 2 則擴展對於 windows 和 macOS 的支援。 > 雖然表面上支援市面上多數作業系統,但在 windows 和 macOS 上運行時還是常會遇到滿滿的 bug,故推薦還是以 docker 或是 wsl 在 linux 系統中運行。 ## 放鬆一下 關於標題的統一回答:不行,他不能幫你在 Deadline 以前趕出作業。 >[!Caution] 厭煩 好爛喔!那他到底可以幹嘛? 他可以幹的事可多了!說不定你夠有能力,給他施點 AI 的魔法,他說不定能夠控制好幾個機器人,同步幫你完成不同的工作、順便還能幫你拿個外賣,讓你有更多時間能拿去陪女朋友逛逛街、看看電影! >[!Tip] 興奮 尊都假都,我要學我要學!MVP、MVP! section - 1 的作業寫完了沒有! >[!Caution] 齁某 阿阿阿阿阿阿阿(悲) ## Node 簡介 ROS 中,節點(Node)為最基本的運作單位,各自管理著單一任務。例如: - 發布、接收 topic 的訊息 - 控制機器人移動 - 處理圖像辨識 ### 創建一個 Node 我們用 python 來做個範例。 ```python= class HelloPublisher(Node): def __init__(self): super().__init__('hello_publisher') # 建立一個名為 hello_publisher 的節點 ... ``` 如上,我們在第三行即向我們的 package 註冊了一個名為 `hello_publisher` 的 node。 >[!Tip] 一個 Package 中 Node 的名字必須為一。 ## Publisher、Subscriber 和 Topic 簡介 小明是個喜歡玩 dota 遊戲的有為青年,因為覺得自己的操作特別厲害、和隊友的溝通非常有(ㄇㄟˊ )效(ㄇㄚ),故想創一個 youtube 頻道上傳自己的遊玩精華。 而小明的爸爸非常欣賞兒子的言談,認為小明的影片是他每天睡前唯一的娛樂,故到小明的 youtube 頻道按下了訂閱,這樣每當小明發了新影片,爸爸就會收到通知。 ![截圖 2025-04-05 晚上7.44.33](https://hackmd.io/_uploads/r1SF_qAayx.png) > 非當事小明。圖片出處:[⚡小明劍魔⚡原版影片:我老爸得了MVP!](https://www.youtube.com/watch?v=ldOn4FfS98A&t=69s&ab_channel=%E8%98%AD%E6%9E%97%E6%BC%A2%E7%9A%84%E7%B2%89%E7%B5%B2-%E7%8C%B4%E5%93%A5%E5%B0%88%E5%B1%AC%E7%B2%BE%E8%8F%AF%E9%A0%BB%E9%81%93) 此處的 youtube 頻道即可對應到 topic,而小明就扮演著 publisher 的角色,持續的發布新消息到 topic,而爸爸在此處則對應到了 subscriber,不斷地從 topic 接收 publisher 們所發布的消息。 ## ROS 安裝 > 這裡只寫到如何在 Ubuntu 中安裝,因為應用場景最廣泛。 > 如有其他環境、系統有安裝需求可於 [Installation — ROS 2 Documentation](https://docs.ros.org/en/humble/Installation.html) 中查詢。 1. 安裝所需 Package ```bash sudo apt update && sudo apt install -y curl gnupg lsb-release ``` 2. 加上 ROS 公鑰、來源列表 ```bash sudo curl -sSL https://raw.githubusercontent.com/ros/rosdistro/master/ros.key -o /usr/share/keyrings/ros-archive-keyring.gpg echo "deb [signed-by=/usr/share/keyrings/ros-archive-keyring.gpg] \ https://packages.ros.org/ros2/ubuntu \ $(. /etc/os-release && echo "$UBUNTU_CODENAME") main" \ | sudo tee /etc/apt/sources.list.d/ros2.list > /dev/null ``` 3. 安裝 ROS 輕量版(沒有 GUI) ```bash sudo apt update sudo apt install -y ros-humble-ros-base ``` 4. 設定環境變數 ```bash echo "source /opt/ros/humble/setup.bash" >> ~/.bashrc source ~/.bashrc ``` > 看你是什麼 Shell 存入對應設定檔中(例如 fish shell 就是存入 config.fish) 5. 安裝建置工具 ```bash sudo apt install -y python3-colcon-common-extensions \ python3-argcomplete \ build-essential ``` ## ROS 使用範例 > 最好在 linux、mac、wsl 中運行 1. 建立、進入工作區。 ```bash mkdir -p ~/ros_ws/src cd ~/ros_ws/src ``` 2. 建立以 Python 編寫的 Package。 ```bash ros2 pkg create --build-type ament_python my_package ``` > my_package 為 Package 名稱,可自行替換。 ``` my_package/ ├── my_package/ │ └── __init__.py ├── package.xml ├── setup.cfg ├── setup.py ``` > 這會直接幫你建立目錄結構。 3. 進入 `my_package/my_package` 中加入兩個節點,一個 Publisher、一個 Subscriber,一個負責投送 `問天地好在`,一個負責接受到的訊息輸出。 ```bash cd my_package/my_package touch hello_publisher.py hello_subscriber.py ``` `hello_publisher.py`: ```python= import rclpy from rclpy.node import Node from std_msgs.msg import String class HelloPublisher(Node): def __init__(self): super().__init__('hello_publisher') self.publisher_ = self.create_publisher(String, 'hello_topic', 10) self.timer = self.create_timer(1.0, self.timer_callback) def timer_callback(self): msg = String() msg.data = '問天地好在' self.publisher_.publish(msg) self.get_logger().info(f'發佈:{msg.data}') def main(args=None): rclpy.init(args=args) node = HelloPublisher() rclpy.spin(node) node.destroy_node() rclpy.shutdown() if __name__ == '__main__': main() ``` `hello_subscriber.py`: ```python= import rclpy from rclpy.node import Node from std_msgs.msg import String class HelloSubscriber(Node): def __init__(self): super().__init__('hello_subscriber') self.subscription = self.create_subscription( String, 'hello_topic', self.listener_callback, 10 ) def listener_callback(self, msg): self.get_logger().info(f'收到訊息:{msg.data}') def main(args=None): rclpy.init(args=args) node = HelloSubscriber() rclpy.spin(node) node.destroy_node() rclpy.shutdown() if __name__ == '__main__': main() ``` 4. 設定 `setup.py`,加入剛建立的兩個 Node。 `setup.py`: ```python= from setuptools import setup package_name = 'my_package' setup( name=package_name, version='0.0.0', packages=[package_name], data_files=[ ('share/ament_index/resource_index/packages', ['resource/' + package_name]), ('share/' + package_name, ['package.xml']), ], install_requires=['setuptools'], zip_safe=True, maintainer='你的名字', maintainer_email='你@email.com', description='Simple ROS 2 Publisher and Subscriber example', license='MIT', tests_require=['pytest'], entry_points={ 'console_scripts': [ 'hello_publisher = my_package.hello_publisher:main', 'hello_subscriber = my_package.hello_subscriber:main', ], }, ) ``` 5. 在 `package.xml` 中檢查 Dependencies,確認包含以下兩者。 `package.xml`: ```xml= <exec_depend>rclpy</exec_depend> <exec_depend>std_msgs</exec_depend> ``` 6. Build + Source(讓 Terminal 知道有這個指令集可供使用)。 回到根目錄並 build: ```bash cd ~/ros2_ws colcon build ``` build 完後會自動出現 `install` 這個資料夾,我們要 source 其中的 `setup.bash` 讓我們能夠執行這個 ROS Package。 ```bash source install/setup.bash ``` > 每次重開新的 Terminal 視窗都需要重新 source 一次,除非加入 Terminal 設定檔中(不推薦) 7. 開啟兩個 Terminal 視窗,並都先到工作區 source 一次 ```bash cd ~/ros_ws source install/setup.bash ``` 於第一 Terminal 開始 Publisher: ```bash ros2 run my_package hello_publisher ``` 於第二 Terminal 開始 Subscriber: ```bash ros2 run my_package hello_subsriber ``` 若成功了將會看到兩 Terminal 互相傳送、接收訊息: ```bash [hello_publisher] 發佈:問天地好在 [hello_subscriber] 收到訊息:問天地好在 ``` > 更多相關語法、指令可自行於 [ROS docs](https://docs.ros.org/) 中查詢。 ## 參考資料 [ROS: Home](https://ros.org/) [zh_tw - ROS Wiki](https://wiki.ros.org/zh_tw) [機器人作業系統 - 維基百科,自由的百科全書](https://zh.wikipedia.org/zh-tw/%E6%A9%9F%E5%99%A8%E4%BA%BA%E4%BD%9C%E6%A5%AD%E7%B3%BB%E7%B5%B1)