Try   HackMD

ROS1 Tutorial Introduction

此篇為中央大學數學系上課所用的 ROS 教材,若非修課生,Demo 部分需要注意一下自己的機器人設定。 若發現教材有誤,歡迎直接修改

主要更新以 hackmd 為主:https://hackmd.io/@Mes/RosTutorial_Intro

什麼是 ROS?

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

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

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

為什麼需要 ROS?

最一開始的狀況

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

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

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

框架

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

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

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

ROS 的架構

Peer to peer (P2P)

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

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

(image source:wikipedia)


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

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

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

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

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

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

(image source:link)


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

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

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

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

(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 Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

(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 來使用,舉個例子(來源):

#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,看看下面這張圖:

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

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

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

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

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

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

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

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

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

資訊的傳遞

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

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

一開始 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

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

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

roscore

rosrun

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

rosrun <package> <executable>

# example
rosrun hypharos_minibot main

roslaunch

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

# 因為launch file 是放在某個package底下,還是要加package
roslaunch <package> <launch file>

# example
roslaunch hypharos_minibot project_sample.launch

rosnode & rostopic

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

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

rosnode

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

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 中提供以下幾種動作可以使用

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

# initialize ros master
roscore

# launch turtlesim_node
rosrun turtlesim turtlesim_node

# using keyboard to control the turtle
rosrun turtlesim turtle_teleop_key
Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

Minibot & Turtlebot

網路設定

筆電網卡設定

>ipv4>ip :10.0.0.2>mask :255.255.255.0>store

gedit ~/.bashrc
Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

source ~/.bashrc
Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

連線

使用新版VM

啟動機器人的指令,一定要在機器人上執行!!

# ssh連接機器人
ssh pi@10.0.0.1 ##passward=mrlrobot

# 假如是minibot下
roslaunch hypharos_minibot project_sample.launch

# 假如是turtlebot下
roslaunch turtlebot3_bringup turtlebot3_robot.launch

起動 rviz 視覺化套件

rviz

遙控機器人

# Extra moving !!!
# 假如是minibot下
roslaunch teleop teleop_key.launch model:=minibot

# 假如是turtlebot下
roslaunch teleop teleop_key.launch model:=turtlebot

如果你長時間都會使用某一台機器人,你可以透過更改環境變數來設定預設機器人

gedit ~/.bashrc

找到以下這兩行(139行以及140行)

可以看到現在預設是使用 minibot,你若是想預設 turtlebot 只要將 139 行反註解、140 行註解掉即可

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

你一定會遇到的問題

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

這代表你電腦中儲存的 Key 跟機器人上的不符合,你就執行他提示的指令

ssh-keygen -f ...

去把它移除,再重新 ssh

catkin

簡介

catkin 是一個開發環境整合套件,C++ 中的 make 幫我們做到在編譯這個層級做整合。在不使用 IDE 的情況下,我們如果要編譯一個 c code 或一個 c project 時需要手動透過指令執行,而當這你的 code import 的函式庫很多或你的 project 很大時需要輸入的指令就會變得十分的複雜

此時 make 這個套件就可以讓我們透過設定一個簡單的 makefile 讓編譯器自動地去建構你所撰寫的project。makefile 會將程式分成好幾個模組,根據裡面的目標 (target)、規則 (rule) 和檔案的修改時間進行判斷哪些需要重新編譯,可以省去大量重複編譯的時間,這在大型程式中尤為有用

而 catkin 這個套件則在 make 的基礎上加入了空間上的整合,讓你整個專案的開發有個統一的格式

使用

catkin 大致上把一個工作區劃分為以下三個區塊

  • src
    用來存放 source code 以及各個 project 的地方,src 中的存放單位為 package
  • build
    用來放程式碼在編譯過程中的中間產物
  • devel
    編譯完的執行檔跟一些環境變數設定檔都會放置在這
Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

後兩個路徑由 catkin 系統自動生成、管理,我們日常的開發一般不會去涉及,而主要用到的是 src 資料夾,我們寫的 ROS 程式、網上下載的 ROS 原始碼包都存放在這裡

在編譯時,catkin 編譯系統會遞迴的查詢和編譯 src/ 下的每一個原始碼包。因此你也可以把幾個原始碼包放到同一個資料夾下,如下圖所示:

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

package結構

├── CMakeLists.txt    # package的編譯規則(必須)
├── package.xml       # package的描述資訊(必須)
├── src/              # 原始碼檔案
├── include/          # C++標頭檔案
├── scripts/          # 可執行指令碼
├── msg/              # 自定義訊息
├── srv/              # 自定義服務
├── models/           # 3D模型檔案
├── urdf/             # urdf檔案
├── launch/           # launch檔案

package的建立

catkin_create_pkg test_pkg roscpp rospy std_msgs

建立一個 package 需要在 catkin_ws/src 下,用到 catkin_create_pkg 命令,用法是:catkin_create_pkg package depends,其中 package 是包名,depends 是依賴的包名,可以依賴多個軟體包

例如,新建一個 package 叫做 test_pkg,依賴 roscpp、rospy、std_msgs(常用依賴)
新建完後就可在 src 中撰寫你的程式碼嘍

編譯package

回到 catkin workspace(catkin_ws) 這層後輸入

catkin_make

他就會自動幫你編譯所有 package

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

編譯完後記得執行以下指令加入環境變數,不然你在 Terminal 上找不到你要執行的 code 喔

source ~/catkin_ws/devel/setup.bash

roscpp

ROS 中的 CPP 檔是放置在 package 中的 src

package結構

├── CMakeLists.txt    #package的編譯規則(必須)
├── package.xml       #package的描述資訊(必須)
├── src/              #原始碼檔案
├── include/          #C++標頭檔案
├── scripts/          #可執行指令碼
├── msg/              #自定義訊息
├── srv/              #自定義服務
├── models/           #3D模型檔案
├── urdf/             #urdf檔案
├── launch/           #launch檔案

node simple sample

cd ~/catkin_ws/src/<your_pkg>/src # 到你的 project 中的 src 中,src 是用來存放 source code 的地方
gedit file_name.cpp # 新增一個 cpp 檔,並編輯。就是開始打 code 啦
#include <ros/ros.h>                             // 引用 ros.h 檔

int main(int argc, char** argv){
    ros::init(argc, argv, "hello_cpp_node");     // 初始化 hello_cpp_node
    ros::NodeHandle handler;                     // node 的 handler
    ROS_INFO("Hello World!");                    // 印出 Hello World
}

cpp 檔不像 python 檔一樣可以直接被執行,需要經過編譯以後才能轉成執行檔,因此我們需要修改 beginner_tutorial 內的 CMakeLists.txt ,為其設定好連結的函式庫
由於他的 CMakeLists.txt 太長了,在此擷取片段做為參考:

cd ~/catkin_ws/src/<your_pkg> # 到你的project中
gedit CMakeLists.txt # 修改當中的 CMakeLists.txt,這是編譯的設定檔
//...上略
## Declare a C++ executable
## ...
## ...
## ...

add_executable(file_name src/file_name.cpp)
target_link_libraries(file_name ${catkin_LIBRARIES})

## Rename C++ executable without prefix
//...下略

修改完 CMakeLists.txt 後,接著須回到工作區的根目錄,也就是 /catkin_ws 中再執行一次catkin_make,他就會自己幫我們編譯好 file_name.cpp 的執行檔(file_name)囉!

接下來修改 file_name.cpp,一樣新增一個迴圈,讓他在程式執行期間每秒印出一個 hello world出來,程式碼如下:

#include <ros/ros.h>                             // 引用 ros.h 檔

int main(int argc, char** argv){
  ros::init(argc, argv, "hello_cpp_node");     // 初始化hello_cpp_node
  ros::NodeHandle handler;                     // node 的 handler
  while (ros::ok()){                           // 在 ros 順利執行時
    ROS_INFO("Hello World!");                // 印出 Hello World
    ros::Duration(1).sleep();                // 間隔 1 秒
  }
}

修改完 file_name.cpp 後,因為 CMakeLists.txt 已經改好了,只要再回去執行一次 catkin_make,就可以重新編譯出一個新的 file_name 囉!

教學傳送門

Publisher simple sample

#include "ros/ros.h"
#include "std_msgs/String.h"
#include <sstream>

int main(int argc, char **argv)
{
  ros::init(argc, argv, "talker");
  ros::NodeHandle n;
  ros::Publisher chatter_pub = n.advertise<std_msgs::String>("chatter", 1000); 
  ros::Rate loop_rate(10);

  int count = 0;
  while (ros::ok())
  {
    std_msgs::String msg;
    std::stringstream ss;
    ss << "hello world " << count;
    msg.data = ss.str();

    ROS_INFO("%s", msg.data.c_str());
    chatter_pub.publish(msg);
    ros::spinOnce(); 
    loop_rate.sleep();
    ++count;
  }
  return 0;
}

教學傳送門

Subscriber simple sample

#include "ros/ros.h"
#include "std_msgs/String.h"

void chatterCallback(const std_msgs::String::ConstPtr& msg)
{
  ROS_INFO("I heard: [%s]", msg->data.c_str());
}

int main(int argc, char **argv)
{
  ros::init(argc, argv, "listener");
  ros::NodeHandle n;
  ros::Subscriber sub = n.subscribe("chatter", 1000, chatterCallback);
  ros::spin();
  return 0;
}

教學傳送門

rospy

ROS 中的 Python 檔是放置在 package 中的 scripts!!!

package結構

├── CMakeLists.txt    # package的編譯規則(必須)
├── package.xml       # package的描述資訊(必須)
├── src/              # 原始碼檔案
├── include/          # C++標頭檔案
├── scripts/          # 可執行指令碼
├── msg/              # 自定義訊息
├── srv/              # 自定義服務
├── models/           # 3D模型檔案
├── urdf/             # urdf檔案
├── launch/           # launch檔案

node simple sample

#!/usr/bin/env python
import rospy                             # import rospy 模組

rospy.init_node('hello_python_node')     # 初始化 hello_python_node

while not rospy.is_shutdown():           # 在 rospy 還沒結束前,執行下列指令:
    rospy.loginfo('Hello World')         # 印出 Hello World
    rospy.sleep(1)                       # 間隔 1 秒

編輯完code後幫code加權限

chmod +x file_name.py

教學傳送門

Publisher simple sample

#!/usr/bin/env python
# license removed for brevity
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

教學傳送門

Subscriber simple sample

#!/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)
    # spin() simply keeps python from exiting until this node is stopped
    rospy.spin()

if __name__ == '__main__':
    listener()

教學傳送門

Robot source code on github

minibot sample code

https://github.com/kuoshih/hypharos_minibot

turtlebot sample code

https://github.com/MathRoboticsLab/turtlebot3_sample

Python for TB3 & minibot:

https://github.com/MathRoboticsLab/hypharos_minibot_turtlebot_python_sample

參考資料

1. jserv ROS 教學

2. ROS Introduction

3. ROS: an open-source Robot Operating System

4. Peer-to-peer wiki

5. ROS WIKI

6. catkin tools

7. ROS自學筆記

8. 這人台大