ROS Tutorial Introduction

ROS Tutorial Introduction

此篇為中央大學數學系上課所用的 ROS 教材,若非修課生,Demo 部分需要注意一下自己的機器人設定。 原文放在 hackmd 上,我會不定期更新過來,若發現教材有誤,歡迎到 hackmd 上修改,或是可以發 issue 給我。

什麼是 ROS?

ROS 全名叫 Robot Operating System,但它其實是一種中介軟體(Middleware),妳也可以說它是一個軟體框架(Software Framework),所以他是一種抽象化的概念,不是應用程式,也不是作業系統。

那它主要會幫我們連結各個軟體和零件之間的溝通,並且會提供一些 logging 的工具,那機器人的中介軟體有很多,像是 ROS、JAUS、Mira 等等。

為什麼需要 ROS?

最一開始的狀況

最一開始大家都各寫各的,但要寫機器人是一件非常困難的事,妳需要熟知如何撰寫每種零件的 code,當然,有大神克服了,完成了很多作品。

然而當日子一久,機器人技術的規模和範圍不斷擴大,零件也越來越多,此時前面那位大神的 code 在別人手上可能就跑不起來了,因為零件不同。

這會造成一個問題,就算是同樣的功能的 code,由於每個人的零件不同,所以都還要再重寫一次,這就導致了代碼的重用性很低(重造輪子),而且這類 code 的規模很大,而且還是需要從驅動層級開始寫的,因此非常不方便,且需要非常高的專業能力。

框架

因此就有人提出了框架的想法,什麼是框架? 框架是一種規則(思想),其實就是某種半成品,框架提供了一個基礎的架構,就好像房子的地基和骨架一樣,必須配合妳自己寫的 code 才能生出一個完整的應用程式。

好處就是整個結構可以被重複使用,如果有了框架,那麼做東西就不需要再從頭建造了。

而前面也提到 ROS 算是一種軟體框架,ROS 幫我們把硬體與軟體之間的溝通都做好了,我們只需要寫我們「溝通的過程/效用」就好,而不用再從「溝通的原理」開始寫,也因此我們可以專注於開發演算法及其應用,同時也降低了高度專業能力的限制。

ROS 的架構

Peer to peer (P2P)

ROS 主要是依靠 P2P 架構實作的,講這個之前先讓大家稍微理解一下簡單的主從式架構:

image source:wikipedia

客戶端(clients) 會去向伺服器請求資料,這邊這個伺服器裡面有很多資料,像是客戶的帳密、金額,或是你遊戲帳號裡面的寶物有哪些之類的。以早期的線上遊戲來說,每次客戶端有更改資料的動作時都會發送一個請求(request) 給伺服器,假設你打了怪,賺到了 10 元,它就會把這個資訊送到伺服器上,伺服器就會幫你記錄下來;

而如果拿網頁舉例子,像是 FB,妳點了某個人的個人頁面,妳就會向伺服器發送一個請求(request),伺服器收到這個請求後就會知道妳要進入這個人的個人頁面,因此將妳導向這個人的個人頁面,妳就成功進去了。

因此伺服器的權限非常的大,並且可以處理非常多的東西。

但這會有一個問題,那就是如果發送請求的人非常多,且請求發送的非常頻繁,那麼伺服器的速度可能就會變得非常慢,甚至當機掛掉,DDoS 的原理就是這樣。

那如果 ROS 使用了主從式架構,很有可能也會有類似的問題,因此 ROS 使用的是 Peer-To-Peer (一種分散式系統架構),Middleware 通常都會是分散式系統架構:

image source:link

在這種架構下,每台電腦(節點)都同時是客戶端與伺服器端,所有人都負責儲存了全部或部分的所有資料,並且也都會處理收到的請求。

這樣做的優點是能夠擁有很好的平行處理能力,效能也會比較好,缺點是如果規模太大整個網路會很亂,且會很吃網路,但因為機器人的網路規模通常很小,所以不太會有這個問題,另一個缺點就是安全性,如果沒有做特別的處理,傳輸的文件可能會被動手腳,或是失真。

那 p2p 有一些變型,這邊舉三個例子,看下面這張圖:

image source:link

上面這三個分別為

  1. 中心化P2P

    英文為 Centralized P2P architecture

    • 有一個中心伺服器來幫忙連結溝通其他節點的訊息資料,並對這些請求做出回應 (但本身並不保存檔案)
    • 節點負責處理、發布訊息資料,讓中心伺服器知道節點需要什麼檔案、資料,讓其他節點下載資源
    • 有 index 可以找到絕對地址

    例子像是最初的 Napster

  2. 純P2P

    英文為 Pure P2P architecture

    • 節點同時是客戶端和伺服器端
    • 沒有中心伺服器

    例子像是 Gnutella

  3. 混合型P2P

    英文為 Hybrid P2P architecture

    • 有多個伺服器來處理其他節點的訊息資料
    • 同時有上面兩個的特性

    例子像是 Skype

那麼 ROS 的架構是第一種,Centralized P2P:

image source:RSL ROS Tutorial

我們會有一片樹梅派來跑 server 的 code,或是像我們一樣用主機來跑 server 的 code,然後各個零件能夠互相傳遞、存取資料。

架構及名詞解釋

現在我們已經知道 ROS 是用 P2P 來實作的了,那麼現在我們要來簡單看一下這些東西在 ROS 裡面的名詞及概念。

Node

在 ROS 裡面,P2P 架構裡面的一個節點我們叫他 Node,Node 是一個你跑起來的程序(Process),一個完整的系統會有很多個 Node。

一個 Node 通常會是有單一功能的 Process,當然妳一個 Node 要有很多功能也可以,總之核心概念就是模組化(Modular Design)。

舉個例子,一個簡單的導航程式,裡面可能是有一個 Node 是操控雷達,一個 Node 操控馬達、輪子,一個 Node 計算自己的定位(Localization),一個 Node 來計算路徑規劃,一個 Node 顯示圖形介面,等等。

所以你可以看見它其實就是很多個 Process 組合起來的,那麼這些 code 妳可以用 roscpp 或 rospy 來寫,好像還有其他另外支援的語言套件,但我只熟這兩個了。

Master

Master 是一個特殊的 Node,也就是我們前面所說的 Server,Master 會幫忙查找 Node,紀錄妳想傳遞的訊息的種類等等。

如果沒有 Master,Node 與 Node 間會找不到對方,妳的資料傳遞、設備呼叫請求等等的溝通就會失效。

Messages

上面有說一個完整的系統會有很多個 Node,那麼 Node 間要傳遞資料需要靠 Messages 來溝通

Message 是一種資料結構,裡面會有 type field,type field 通常指的是一個基類(base class) 裡面的變數,這個變數會拿來當作子類的 type 來使用,舉個例子(來源):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
#include <iostream>

class Pet {
public:
enum PetType { Dog, Cat, Bird, Fish };

void ToString() const {
switch ( type ) {
case PetType::Dog:
std::cout << "Dog" << std::endl;
break;
case PetType::Cat:
std::cout << "Cat" << std::endl;
break;
case PetType::Bird:
std::cout << "Bird" << std::endl;
break;
case PetType::Fish:
std::cout << "Fish" << std::endl;
break;
}
}

protected:
PetType type; // A type field.
};

class Dog : public Pet {
public:
Dog() { type = PetType::Dog; }
};

void Test( const Pet &p ) {
p.ToString();
}

int main() {
Dog d;
Test( d );
return 0;
}

上面的 Pet::type 就是一個 type field,在 Dog 這個子類裡面我們用 type 來當作了它的型態。

Messeage 裡面可以有標準的基本型態,整數、浮點數、布林值之類的,也可以是基本型態的陣列,且 Message 內可以包含巢狀類(nested class)。

Topic

Message 在發布時我們會給它加上 Topic,妳可以把 Message 想像成一個箱子,Node 間要傳遞資料時會把資料放到這個箱子裡面,並在這個箱子上面貼上一個標籤,這個標籤就是 Topic。

覺得太抽象的話可以看下面那個小節的圖。

Publisher & Subscriber

讓我們先小整理一下,Message 是 Node 間拿來溝通的工具,因此 Message 由 Node 發布,也由 Node 接收。

於是在 ROS 裡面,發布 Message 出來的 Node 我們叫它 Publisher,接收 Message 的 Node 我們叫它 Subscriber,看看下面這張圖:


Node 會通過 Topic 來找要接收它需要的訊息,我們稱之為訂閱,例如規劃路徑的 Node 希望和雷達的 Node 拿掃到的資料,那麼規劃路徑的 Node 就是 Subscriber,雷達的 Node 則是 Publisher

而 Message 裡面可能裝很多個整數的陣列,Topic 可能是「雷達資料」,以上方那個圖來說就是:

而同一種 Topic 的 Message 也可以由不同的 Node 發布,也就是有不同的 Publisher 發布同樣 Topic 的 Message; 例如妳雷達有兩顆,而且妳為他們寫了兩個 Node,那麼這兩個 Node 都可以發布「雷達資料」這種 Topic 的 Message:

同理,同一種 Topic 的 Message 也可以有不同的 Node 訂閱,有就是有不同的 Subscriber 訂閱同樣 Topic 的 Message; 例如規劃路徑的 Node 需要雷達的資料,建地圖的 Node 也需要雷達的資料,那這兩個 Node 都可以訂閱「雷達資料」這種 Topic 的 Message。

如果一個 Node 同時在收資料與發資料,那這個 Node 就同時是 Subcriber 與 Publisher。

資訊的傳遞

實際上在傳遞資訊時還會需要 Master 來幫忙 Node 之間的通訊,那麼 ROS 的訊息傳送時是使用 TCP/IP 協定的連線,且一旦兩個訊息接起來後就不會再經過 Master 了:

一開始 Publisher 會先去向 Master 註冊,然後 Publisher 就會開始發布它的訊息(封包);而當 Subscriber 需要相對應的訊息時就會去詢問 Master,那當它訂閱到那個 Topic 時它們就建立了連線,不再透過 Master 來傳遞資訊。

所以 Master 會負責 Node 之間的通訊,他們之間是 TCP/IP 協定的連線。

而因為 Middleware 會做序列化(Serialization),所以你 C++ 寫出來的 Node 和 Python 寫出來的 Node 也可以溝通。

Package

Package 是一個 ROS 軟體的基本單位,Package 會有裡面會有很多個 Node,然後可能會包含有相關的函式庫、資料集(dataset)、配置文件(configuration file),或其他能幫助你整合、規劃專案的檔案。

換句話說,Package 是妳在建立和發布專案時最基本的單位,因為妳的專案很可能是程式與程式之間在溝通的,妳把那些 Node 整合起來,配合妳自己寫的函式庫,蒐集的資料等等的,整個包裝起來成一個能讓別人使用的程式,這樣的東西就是一個 Package。

Demo (By OG)

VB image

Ubuntu & Linux

Ubuntu是基於Debian,以桌面應用為主的Linux發行版。Ubuntu有三個正式版本,包括電腦版、伺服器版及用於物聯網裝置和機器人的Core版。前述三個版本既能安裝於實體電腦,也能安裝於虛擬電腦。

Terminal & CLI

linux 基本指令 :

cd:用以移動到目標路徑

cp:複製檔案到指定路徑

mv:移動檔案到指定路徑

rm:刪除檔案

ls:顯示當前路徑下的資料夾與檔案

nano:一種CLI的編輯軟體

vim:一種CLI的編輯軟體

SSH :

Secure Shell是一種加密的網路傳輸協定,可在不安全的網路中為網路服務提供安全的傳輸環境。SSH通過在網路中建立安全隧道來實現SSH客戶端與伺服器之間的連接。SSH最常見的用途是遠端登入系統,人們通常利用SSH來傳輸命令列介面和遠端執行命令。

ssh username@server_location -p port

username:遠端操作時的使用者帳號

server_location:你要連接的電腦,可能是ip或URI

port:ssh 專用的port,預設為22

請注意,接下來開始會有兩台主機進行運作。一台是你的電腦,一台是機器人。
請留意你到底是在哪台機器上操作!!!

ROS

roscore & rosrun & roslaunch

在運行node之前都必須先啟動master,master就是ROS系統中負責管理Node的一個功能,他負責node與node之間的溝通橋樑,因此在執行node之前一定要先把master開啟。然後在ros中提供兩種方法去執行你的Node,一種是rosrun、一種是roslaunch。

roscore

roscore可以讓你啟動master

1
roscore

rosrun

rosrun可以讓你去執行特定package下的code,使用方法如下

1
2
3
rosrun <package> <executable>
## exaple
rosrun hypharos_minibot main

roslaunch

roslaunch則透過預先設定的launch file幫你一次開啟很多程式

1
2
3
4
## 因為launch file 是放在某個package底下,還是要加package
roslaunch <package> <launch file>
## example
roslaunch hypharos_minibot project_sample.launch

rosnode & rostopic

在ros中你可以使用以下兩種指令去檢視正在運行的node及topic

  • rosnode 動作 參數
  • rostopic 動作 參數

rosnode

在rosnode中提供以下幾種動作可以使用

1
2
3
4
5
6
rosnode info <node_name>       #print information about node
rosnode kill <node_name> #kill a running node
rosnode list #list active nodes
rosnode machine <machine-name> #list nodes running on a particular machine or list machines
rosnode ping <node_name> #test connectivity to node
rosnode cleanup #purge registration information of unreachable nodes

rostopic

在rostopic中提供以下幾種動作可以使用

1
2
3
4
5
6
7
8
9
rostopic bw <topic_name>                          #display bandwidth used by topic
rostopic delay <topic_name> #display delay for topic which has header
rostopic echo <topic_name> #print messages to screen
rostopic find <msg-type> #find topics by type
rostopic hz <topic_name> #display publishing rate of topic
rostopic info <topic_name> #print information about active topic
rostopic list #print information about active topics
rostopic pub <topic-name> <msg-type> [data...] #publish data to topic
rostopic type <topic-name> #print topic type

機器人初連接

Turtlesim

1
2
3
4
5
6
7
8
# initialize ros master
roscore

# launch turtlesim_node
rosrun turtlesim turtlesim_node

# using keyboard to control the turtle
rosrun turtlesim turtle_teleop_key

Minibot & Turtlebot

網路設定

筆電網卡設定
–>ipv4–>ip :10.0.0.2–>mask :255.255.255.0–>store

1
gedit ~/.bashrc

1
source ~/.bashrc

連線

使用新版VM
啟動機器人的指令,一定要在機器人上執行!!!

1
2
3
4
5
6
# ssh連接機器人
ssh pi@10.0.0.1 ##passward=mrlrobot
# 假如是minibot下
roslaunch hypharos_minibot project_sample.launch
# 假如是turtlebot下
roslaunch turtlebot3_bringup turtlebot3_robot.launch

起動 rviz 視覺化套件

1
rviz

遙控機器人

1
2
#Extra moving !!!
roslaunch teleop teleop_key.launch