# Robot Operating System
:::info
整理者:黃智彬
:::
# Abstract
機器人作業系統Robot Operating System,簡稱ROS,是由
# Install of the Ubuntu
### 1. Windows subsystem for Linux(WSL)
1. 確認電腦Windows版本需要在Win10 21H2或Win11以上。
2. 在PowerShell中打入:
``` command
wsl --install -d Ubuntu-20.04(版本號)
```
#### <font color="bull">PowerShell重要指令</font>
系統更新:```wsl --update```
列出可安裝版本:```wsl --list --online```
列出狀態:```wsl --list --verbose ``` 簡寫 ```wsl -l -v```
關機:```wsl --terminate 系統名稱``` 或 ```wsl --shutdown```
刪除,真的實體刪除:```wsl --unregister 系統名稱```
#### <font color="bull">第一次啟動Ubuntu </font>
在Windows的開始視窗中找到Ubuntu,即可開啟,進入後第一次輸入自己的名稱與密碼。
#### <font color="bull">系統實體位置</font>
整個虛擬系統的實體位置:
C:\Users\你的帳號名稱\AppData\Local\Packages\CanonicalGroupLimited………
#### <font color="bull">系統移植</font>
**將系統關機:**```wsl --terminate ubuntu-20.04```
**將實體檔案複製到其他地方:**```wsl --export ubuntu-20.04 d:\ubuntu-20.04.tar```
**刪除原有系統檔案:**```wsl --unregister ubuntu-20.04```
**利用檔案總管,在後續需要的地方建立資料夾,例如d:\wsl\ubuntu-20.04**
**匯入實體檔案:**```wsl --import ubuntu-20.04 d:\wsl\ubuntu-20.04\ d:\ubuntu-20.04.tar```
**刪除備份資料:**```del d:\ubuntu-20.04.tar```
### 2. VM Virtual Box
### 3. Docker
# ROS安裝
## STEP
**正規安裝(版本:Ubuntu18.04/ROS melodic)**
1. 開啟setting,進入Sofeware & Updates,把Source code打勾。
2. 執行以下命令,使電腦允許接收packages.ros.org的軟體
``` command
sudo sh -c 'echo "deb http://packages.ros.org/ros/ubuntu $(lsb_release -sc) main" > /etc/apt/sources.list.d/ros-latest.list'
```
3. 設置金鑰
```
sudo apt install curl
curl -s https://raw.githubusercontent.com/ros/rosdistro/master/ros.asc | sudo apt-key add -
```
4. 確保系統套件是最新的
```
sudo apt update
```
5. 安裝ROS
桌面完整安裝,包含ROS, rqt, rviz, robot通用函式庫,2D/3D模擬器(約10GB)。
```
sudo apt install ros-melodic-desktop-full
```
桌面安裝:包含ROS, rqt, rviz, robot通用函式庫。
```
sudo apt install ros-melodic-desktop
```
ROS輕量板:只有ROS包,通訊庫。
```
sudo apt install ros-melodic-ros-base
```
安裝特定套件:
```
sudo apt install ros-melodic-PACKAGE
```
安裝完後確認目前的可用套件:
```
apt search ros-melodic
```
6. 將ROS的環境變數添加至bash文件中
```
echo "source /opt/ros/melodic/setup.bash" >> ~/.bashrc
source ~/.bashrc
```
7. 用於生成ROS包的依賴項
```
sudo apt install python-rosdep python-rosinstall python-rosinstall-generator python-wstool build-essential
```
8. 初始化rosdep
```
sudo apt install python-rosdep
sudo rosdep init
rosdep update
```
* catkin build安裝
```
sudo apt-get install python3-catkin-tools
```
**快速安裝**
1. 安裝Git工具
``` command
sudo apt update
```
``` command
sudo apt install -y git curl
```
2. 安裝ROS工具包
``` command
sh -c "$(curl -fsSL https://raw.githubusercontent.com/Adlink-ROS/ros_menu/master/scripts/setup.sh)"
```
3. 測試ROS的功能(Turtle)
Terminal-1
``` command
roscore
```
Terminal-2
``` command
rosrun turtlesim turtlesim_node
```
Terminal-3
``` command
rosrun turtlesim turtle_teleop_key
```
# ROS概述

# ROS的重要觀念
## ROS Architecture

* 3 Layer: OS->middleware->APP
* APPs(Nodes)use ROS library
* Master controls communication
## 檔案架構層
* **ROS中,會有兩個資料夾可以使用**

最常使用的為右邊的workspace資料夾,catkin可以在創建此資料夾時任意更改,這個資料夾主要是用來放置開發用的各種ROS包、標頭檔與Code等檔案。
* **workspace的文件配置**

在workspace的資料夾底下,一定會區分成三個區域,分別是:build, devel, src,其中會動到的資料夾只有src。
* **src**

在ROS中,Node是可執行的文件檔案中最小的單位,Node可以使用C/C++、Python等ROS能支援的語言Coding,並透過ROS特殊的通訊機制將Node組合起來,使其成為一個具有單一功能的Package。( 就算是利用不同語言撰寫的Node也可以在ROS的通訊中傳遞資料)
* **Package資料夾的檔案配置**
上述所言,雖然Package是由一大堆的Node組合而成的,但將所有的Node全部扔在Package中未免也太雜亂了。
所以ROS定義了一套Package的標準資料夾結構,

以下說明各資料夾:
| File Name | Definition
| -------------- | ----------
| action | 存放自定義的action文件檔案
| config | 存放自定義的動態配置文件檔案
| include | 存放Package會使用的標頭檔案(C)或模組(Python)
| launch | 存放launch文件檔案
| msg | 存放自定義Message文件檔案
| scripts | 存放可直接執行的Python程式碼檔案,或是執行演算法的程式碼檔案
| src | 存放需要進行編譯的C/C++程式檔案,或是直接操作硬體相關的Code
| srv | 存放自定義srv文件檔案
| CmakeLists.txt | 使用catkin_make編譯功能時,所需要的編譯規則
| package.xml | 存放會使用其他package的清單
## 計算圖層
Node在ROS網路中是透過==P2P網路(Peer-to-peer對等式網路)== 與[Point-to-Point Proctocol(PPP)](https://reurl.cc/DXzbYN)的通訊機制進行溝通。
ROS計算圖層的概念包含Node、Topic、Message、Master、Parameter server、Service與bag。
* Node: Node是一個Process,多個Node是使用ROS API進行數據交流。
* Master: 在網路中扮演接線生的角色,Master擁有ROS網路中各個Node的所有資料。將某個Node與其他Node的詳細資料交換來建立起之間的連線,資料交換後,兩個Node就可以開始通訊。
* Parameter Server: ROS把所有Node所使用的變數都放置在Parameter Server,並且可以為每個變數設置隱私權,即訪問權限,以方便篩選需要使用的Node訪問。
* Message: 定義ROS網路中的通訊協定。
* Bag: Bag是ROS中用於紀錄與重播Topic的公用程式。在很多時候我們都得在沒有硬體的強況下操作Robot,透過rosbag,我們得以紀錄感測器的資料,還可以把bag檔copy到另一台電腦來重播,藉以檢查資料的正確性。
## ROS Message
ROS有三種的通訊方法:Topic, Service, Action,以下是它們的概念圖。

---
### <font color="purple">**Topic**</font>
ROS中最常用的通訊方式,為多對多單向且[異步(Asynchronous)](https://baike.baidu.com/item/%E5%BC%82%E6%AD%A5/3441874)的通訊方式,在Topic的通訊機制,具體是透過Node之間傳遞message進行訊息傳輸,適合狀態監控類的任務。
* Publisher(發佈者):
1. 生成訊息,發佈message到對應的Topic上。
2. 通常用於處理原始的Sensor data,如相機、Encoder。
* Subscriber(訂閱者):
1. 接收訊息,訂閱所需的Topic上的message下來使用。
2. 可用於監測系統狀態,如當手臂關節到極限位置時觸發運動中斷。
可以理解成,有一個人將message publish到一個佈告欄(Topic)上,那有需要的人可以subscribe這個佈告欄上的message下來使用,因此為單向的通訊方式。
Subscriber在收到訊息時會先進行處理,稱之為Callback(回調),Callback即為提前定義好一個處理函式(在Process中),當有消息來就會觸發這個處理函式,類似Arduino的中斷(Interrupt)。
``` python
rospy.Subscriber("Topic名稱", message類型, callback_function)
```
message是Node之間傳遞訊息的數據格式,ROS支持[標準數據格式](http://wiki.ros.org/msg)(int8, float16, string),也可以自定義message的類型,當然ROS本身也定義了一套用於Robot的數據格式,包括控制動作的**actionlib_msgs** 、導航用**nav_msgs**、感測器用的**sensor_msgs**,會建議能使用原先提供的message type就先使用,並且遵照其定義的訊息意義使用。
#### Topic通訊特點
1. 多對多的異步通信方式:
Publusher調用publish()發佈消息,發佈完立即返回,不用等待反饋;Subscriber通過Callback的方式來處理message。
對於同一Topic,系統中可以同時存在多個Publisher與Subsciber。
另外,Publisher並不知道哪個Node會接收消息,而Subscriber也不知道接收的消息來自哪裡,Node之間式鬆耦合的,這是ROS最關鍵的設計之一。
2. 對於實時性、週期性的消息,使用Topic傳輸是最佳解。
3. Topic通信方式充分體現出分散式系統通信的好處:擴展性好、軟體複用性高。
#### Topic communcate step

1. Publisher和Subcriber利用[RPC](https://reurl.cc/OEZ6W7)向Master註冊自己的訊息(Node地址等...)。
2. Master確定需要通信的Node後就會對Node的訊息進行匹配。
3. Subscriber向Publisher發送自身的[TCP/IP protocol](https://zh.wikipedia.org/wiki/TCP/IP%E5%8D%8F%E8%AE%AE%E6%97%8F)以及連接請求。
4. Publisher確定連接請求,然後將自身的TCP/IP address發送給Subscriber。
5. 兩個Node正式建立連接,並以TCPIP protocol進行數據傳輸。
#### msg自定義格式
Topic有很嚴格的訊息格式,ROS中message遵照著固定的型態格式。
bool, int8, int16, int32, int64, uint, float32, float64, string, time, duration, header, array, vector(可變長度的array)
msg的範例:
```
std_msg/Header header
uint32 seq
time stamp
string frame_id
uint 32 height
uint32 width
string encoding
uint8 is_bigendian
uint32 step
uint8[] data
```
MSG相關操作命令
|rosmsg指令 |作用
|----------------------| ----
|rosmsg list |列出系統上所有的msg
|rosmsg show "msg_name"|顯示某個msg的內容
#### command window操作命令
|命令 |作用
|:-------------------------------|:----------
|```rostopic list``` |列出當前所有topic
|```rostopic info "topic_name"```|顯示topic的屬性信息
|```rostopic echo "topic_name"```|顯示topic的內容
|```rostopic pub "topic_name"``` |向topic發佈內容
|```rostopic bw "topic_name"``` |查看topic的頻寬
|```rostopic hz "topic_name"``` |查看topic的頻率
|```rostopic find "topic_type"```|查找某個類型的topic
|```rostopic type "topic_name"```|查看topic的類型
---
### <font color="purple">**Service**</font>
為了解決某些Node只是臨時而非週期性的需要某些數據,使用Topic通訊則會消耗大量不必要的系統資源,導致整體系統的低效率高功耗;在這種情況下,Service就是因應此需求而開發的。
Service是透過Request&Response來溝通,屬於單對單的雙向同步通訊方式,它不但可以發送訊息,同時也會得到反饋,並且回應及時。
Service包括兩部分,一部分為**應答方/服務提供方(Server)**,另一部分為**請求方(Client)**。

#### 過程
Client發佈Request後會在原地等待Response,直到Server處理完Request後並且回傳Response,Client才會繼續動作。
Client等待過程中,是處於阻塞的狀態。這種的通信模型沒有頻繁的訊息傳遞,沒有衝突與高系統資源的占用,只有接收Request才執行Service。
#### SRV
SRV是Service的一種訊息格是,跟message很像,其附檔名為.srv,SRV文件包含Request跟Response的格式。
以OpenNI的人體檢測ROS包中的為例:
msgs_demo/srv/DetectHuman.srv
```
bool start_detect
---
my_pkg/HumanPose[] pose_data
```
msgs_demo/msg/HumanPose.msg
```
std_msgs/Header header
string uuid
int32 number_of_joints
my_pkg/JointPose[] joint_data
```
msgs_demo/msg/JointPose.msg
```
string joint_name
geometry_msgs/Pose pose
float32 confidence
```
這個.srv檔用來查詢當前深度鏡頭中的人體姿態和關節數。
.srv檔的格式很固定,第一行為Request的格式,第三行為Response的格式,中間用---隔開。
本例中,Requset為是否開始檢測,Response為一陣列,陣列中的每個元素為某人的姿態(HumanPose)。
而對於人的姿態,其實為一msg,因此srv可以嵌入msg在其中,但相反就不行。
SRV相關操作命令
|rossrv指令 |作用
|----------------|-----
|rossrv show |顯示service描述
|rossrv list |列出所有service
|rossrv md5 |顯示服務md5sum
|rossrv package |列出package中的service
|rossrv packages |列出包含service的package
#### command window操作命令
|命令 |作用
|:---------------------|:---------------
|```rosservice list ```|顯示Service列表
|```rosservice info ```|印出Service訊息
|```rosservice type ```|印出Service類型
|```rosservice uri ```|印出服務ROSRPC uri
|```rosservice find ```|依Service類型查找Service
|```rosservice call ```|使用所提供的args調用Service
|```rosservice args ```|印出Service參數
---
### <font color="purple">**Action**</font>
當機器人執行一個長時間的任務時,如果利用Service,那麼Client會很長時間接收不到Response,此時我們有多工的需求時,Servic會導致通信受阻。
Action就是在這一個背景下開發的,它類似Service的通訊機制,但Action比較適合長時間的通信過程,在Action通信的過程可以隨時查看過程進度,也可以終止過程,這種特性,使得它在一些特別的機制擁有很高的效率。
Action也包括兩部分:
* Action server:向ROS系統廣播指定action的Node,其他Node也可向該Node發出action目標請求。
* Action client:發出action目標請求的Node。
通訊原理示意圖:Action的工作原理是client-server模式,為雙向的通訊。

通信雙方在ROS Action Protocal下進行通信,如下圖。

可以看到,Client(客戶端)會向Server發送目標指令和取消動作的指令,而Server則可以向Client回報實時的Status, result, feedback等訊息,這些都是Service無法完成的。
#### Action 規範
利用Actionlib請求動作時,該動作的內容必須包含三個部分goal, feedback, result。
* Goal(目標)
機器人執行一個動作,應該要有明確的移動目標信息,包括參數的設定、方向、角度、速度等等。從而使機器人完成動作任務。
* Feedback(反饋)
在動作進行的過程中,應有實時的狀態訊息反饋給Client,告訴Client動作完成的狀態,可以使Client作出準確的判斷去修正命令。
* Result(結果)
當動作完成時,Server把動作的結果發送給Client,使Client得到本次動作的全部訊息,如:機器人的運動時長、最終位姿等。
#### Action文件格式
* 文件名稱:<custion_message_type>.action
* 文件副檔名:.action
* 文件位置:<ros_package_name>/action文件夾中
* 內容格式:
``` command
# Define the goal
uint32 dishwasher_id #Specify which dishwasher we want to use
---
# Define tje result
uint32 total_dishes_cleaned
---
# Define a feedback message
float32 percent_complete
---
```
#### Action相關資料
https://sychaichangkun.gitbooks.io/ros-tutorial-icourse163/content/chapter4/4.4.html
https://tr-ros-tutorial.readthedocs.io/zh_CN/latest/_source/basics/1.6_ROS_Action.html
#### 自定義msg, srv, actiion修改部分文件
在添加完自己定義的msg, srv, action檔後,需要修改CMakeLists.txt,使其生效。
```
find_package(catkin REQUIRED COMPONENTS
roscpp
rospy
std_msgs
geometry_msgs #add new line
message_generation #add new line
actionlib #add for action
actionlib_msgs #add for action
)
## Generate messages in the 'msg' folder
add_message_files(
FILES
RobotState.msg ## 自定義的msg檔
)
## Generate services in the 'srv' folder
add_service_files(
FILES
RobotStateService.srv ## 自定義的srv檔
)
## Generate actions in the 'action' folder
add_action_files(
FILES
AutoDocking.action ## 自定義的action檔
)
## Generate added messages and services with any dependencies listed here
generate_messages(
DEPENDENCIES
std_msgs
geometry_msgs
actionlib_msgs
)
```
若有其中的檔案有引用的原本ROS的訊息格式(如:geometry_msgs等...),除了需要在CMakeLists.txt文件中添加訊息的依賴,同時也需要在package.xml中添加該訊息的依賴,如下:
``` xml
<build_depend>geometry_msgs</build_depend>
<build_depend>message_generation</build_depend>
<build_depend>actionlib</build_depend>
<build_export_depend>geometry_msgs</build_export_depend>
<build_export_depend>actionlib</build_export_depend>
<exec_depend>geometry_msgs</exec_depend>
<exec_depend>message_runtime</exec_depend>
<exec_depend>actionlib</exec_depend>
```
修改完後,在運行以下指令編譯即可:
``` cmd
cd ~/"workspace"
catkin_make
```
編譯完後,可透過rosmsg/rossrv show查看定義。
``` cmd
cd ~/"workspace"
source devel/setup.bash
rosmsg show tutorial/RobotState
rossrv show tutorial/RobotStateService
```
### 三種通訊方式的差別
|Type |Featurs |Featurs |Description
|--------|--------------|--------- |--------------
|Topic |Asynchronous |Unidirectional |Used when exchanging data continuosly
|Service |Synchronous |Bi-directional |Used when request processing requests and responds current states
|Action |Asyschronous |Bi-directional |Used when it's difficult to use the service due to long response times after the request or when an intermediate feedback value is needed
# 常用工具
## Rviz
## Gazebo
# 參考文獻
https://www.twblogs.net/a/5bf6f36fbd9eee18ceccf906
https://sychaichangkun.gitbooks.io/ros-tutorial-icourse163/content/chapter1/