# 機器人作業系統能幫我寫作業嗎?ROS 2 究竟是何方神聖
Copyright (c) 2025 NCKU sspfr [section - 2](/0heMGItdRMmcdKViZ7po1Q)
## 前言
作業系統是個相對於直接的硬、軟體比較抽象的一個概念。
舉個例子來講,你今天買了一些電腦零件,好比 cpu、記憶體、主機板等等,開開心心回家組了台電腦,組完後颯爽的按下開機。螢幕除了輸出個 bios 啥都沒有,你還以為自己得了 MVP,結果現在連遊戲都不知道哪裡下載。頓時你想起了 windows 這個作業系統,只要安裝後鍵盤、滑鼠就可以做相對應的輸入,並且控制其他零件例如圖像的輸出、聲音的播放。作業系統即做了一個硬體-硬體間、硬體-軟體間,重要橋樑的工作。
回到機器人,假設你想組台會自己辨識路況的自駕車,你需要哪些零組件?會動要有馬達、馬達會動要有電池、辨識路況要有 sensor、運算 sensor 的回傳資料再決定車要往哪開要有軟體。這些東西加起來要你用 `c / c++` 寫一套韌體自己驅動應該會想死吧!這時候 ROS 就登場了,其可作為良好的橋樑,幫助我們更方便的做硬、軟體間的交互溝通。
## ROS 簡介

ROS 全名 Robot Operating System,顧名思義是類似給機器人使用的作業系統,但此作業系統非彼傳統意義上的作業系統,更像是一套中介軟體,幫助開發者更容易的去建構複雜且強大的機器人軟體。
其開源易上手的特性吸引了不止各大企業使用,亦有不少個人、小團體的開發團隊使用其作為控制自動化、機器人的核心框架。
## ROS 的主要特色
### 模組化架構
ROS 採用節點(Node)架構,把多種功能拆分成一個一個的節點,方便編輯以及後續維護。

> 圖片出處:[The Robotics Backend](https://roboticsbackend.com/what-is-ros/)
### 通訊機制
提供發佈 / 訂閱(Publish / Subscribe)、服務(Service)和動作(Action)等通訊模式,讓各個節點之間能夠有效協作。
### 與硬體搭配
ROS 能夠與多種感測器與執行器整合,讓開發者不必從 kernal 開始編寫。
## ROS 1 和 ROS 2 的區別

> 圖片出處:[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 頻道按下了訂閱,這樣每當小明發了新影片,爸爸就會收到通知。

> 非當事小明。圖片出處:[⚡小明劍魔⚡原版影片:我老爸得了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)