# 基隆xAUV ROS 教學
###### tags: `基隆` `ROS`
![](https://i.imgur.com/ScFzWun.png)
[TOC]
## ROS(Robot Operating System)
ROS 是在 Linux 中的,專門設計來控制機器人與自動化裝置的軟體架構。
#### 基本結構
##### Workspace 工作空間
如果沒有工作空間,那就不能使用 ROS,就假設這是個虛擬平台,連結著所有的節點(node)。
##### Node 節點
節點,就是執行檔。通常會含有發佈者(publisher)和訂閱者(subscriber)
##### Topic 主題
發佈者(publisher)可以發佈訊息(message)到主題,而訂閱者(subscriber)可以訂閱主題以接收訊息(message),用這種方式節點(node)跟節點之間便可以溝通。
##### Package 包裹
包裹中可以存放所需的節點(node)。通常一個包裹代表一個特定的任務,節點則是任務的拆解子任務。
##### Launch file
通常包裹中都會有一個 Launch 資料夾,裡面存放不同的 launch 文件,只要執行一個 launch 文件,便會一次啟動所有需要的節點。
- [ROS自學筆記](https://charlyhuangrostutorial.wordpress.com/ros-%E8%87%AA%E5%AD%B8%E7%AD%86%E8%A8%98/)
![](https://i.imgur.com/p5nDCgf.png)
---
## 啟動 ROS
開啟終端機(ctrl+alt+t)並輸入
```
roscore
```
確認是否有出現類似畫面
![](https://i.imgur.com/xTxRQ5k.png)
:::success
**因為接下來要執行的工作都要確保ROS是啟動狀態
所以要開啟新的終端機(ctrl+alt+t)來執行工作**
:::
---
## 範例 (Python)
### 發佈者(publisher)
```python=
#!/usr/bin/env python3
import rospy
from std_msgs.msg import String
def talker():
rospy.init_node('talker', anonymous=True)
pub = rospy.Publisher('chatter', String, queue_size=10)
rate = rospy.Rate(10) # 10hz
while not rospy.is_shutdown():
hello_str = "hello world"
rospy.loginfo(hello_str)
pub.publish(hello_str)
rate.sleep()
if __name__ == '__main__':
try:
talker()
except rospy.ROSInterruptException:
pass
```
#### 引用(import): 為了使用已經寫好的library
```python=
import rospy
from std_msgs.msg import String
```
#### 節點(node)初始化
```python=
rospy.init_node('talker', anonymous=True)
```
- 'talker': 為節點(node)名稱
- anonymous=True: 確保此節點名稱是唯一的,不會跟其他節點名稱重複
#### 設置發佈者(publisher)參數:
```python=
pub = rospy.Publisher('chatter', String, queue_size=10)
```
- 'chatter': 發佈的主題(topic)名稱
- String: 訊息(message)的資料型態(data type)
- queue_size: 最多暫存資料數
#### 執行迴圈速度
```python=
rate = rospy.Rate(10) # 10hz
```
- 以每秒發佈幾次訊息為單位
#### 發佈訊息(message)
```python=
while not rospy.is_shutdown():
hello_str = "hello world"
rospy.loginfo(hello_str)
pub.publish(hello_str)
rate.sleep()
```
- rospy.is_shutdown(): 為停止發佈訊息(message)的中止條件(ctrl+c)
- rospy.loginfo(hello_str): 其中之一的功能是將發佈訊息(message)顯示到終端機上
- pub.publish(hello_str): 發佈訊息(message)到主題上(topic)
- rate.sleep(): 為了配合執行速度
#### 執行結果
![](https://i.imgur.com/74UNmIA.png)
### 訂閱者(subscriber)
``` python=
#!/usr/bin/env python3
import rospy
from std_msgs.msg import String
def callback(data):
rospy.loginfo("I heard %s", data.data)
def listener():
rospy.init_node('listener', anonymous=True)
rospy.Subscriber('chatter', String, callback)
rospy.spin()
if __name__ == '__main__':
listener()
```
#### 節點(node)初始化
```python=
rospy.init_node('listener', anonymous=True)
```
- 'listener': 為節點(node)名稱
- anonymous=True: 確保此節點名稱是唯一的,不會跟其他節點名稱重複
#### 設置訂閱者(subscriber)參數:
```python=
rospy.Subscriber('chatter', String, callback)
```
- 'chatter': 訂閱的主題(topic)名稱
- String: 訂閱訊息(message)的資料型態(data type)
- callback: 訂閱到訊息後要執行的工作(handle function)
#### handle function:
- 此處為固定形式
```python=
def callback(data):
...
```
#### 重複訂閱
```python
rospy.spin()
```
#### 執行結果
![](https://i.imgur.com/4cdEygo.png)
## 指令
- ```rostopic list```: 列出所有在ROS上存在的所有主題(topic)
- ```rostopic echo /topic-name```: 把發佈(publish)到指定主題(topic)的訊息(message)顯示在終端機上
- ```rosrun package_name node_name```: 執行指定的node(需要開啟roscore)
- ```roslaunch package_name file_name.launch```: 執行指定的launch檔(會自動開啟roscore)
## 連線 ROS Master(開啟roscore的裝置)
1. 連上與master相同的網域
2. 開啟終端機
3. 在終端機輸入 ``ifconfig`` 確認自己裝置的IP
4. 在終端機輸入 ``vim ~/.bashrc``
5. 並在最底下加上
``export ROS_MASTER_URI=http://<ros master的 ip>:11311``
``export ROS_IP=自己裝置的IP``
後儲存後跳出
6. 在終端機輸入 ``source ~/.bashrc``
7. 這樣自己的裝置就能和ROS_Master共用ROS環境
---
## RVIZ
ROS 應用程式的 3D 視覺化工具,它也可以顯示來自於攝影機等資料。
先在終端機輸入```rviz```確認是否有安裝
### 安裝rviz
開啟終端機並輸入
```
rosdep update
rosdep install rviz
rosmake rviz
```
### 啟動rviz
- 開啟樹梅派的終端機並輸入(開啟鏡頭)
```
roslaunch usb_cam usb_cam-test.launch
```
- 將自己的裝置和樹梅派連線後開啟終端機並輸入
```
rviz
```
### 啟動後的畫面
- 終端機(自己)
![](https://i.imgur.com/QoTlcD8.png)
- 終端機(樹梅派)
![](https://i.imgur.com/izLLeF9.png)
- 跳出的視窗(自己)
![](https://i.imgur.com/Ld5vDhh.png)
### 新增攝影機畫面
1. 按下 ***Add***
![](https://i.imgur.com/fPJKfDU.png)
2. 按下 ***By topic***
![](https://i.imgur.com/KFppEDE.png)
3. 按下 ***Image*** 後按 ***OK***
![](https://i.imgur.com/TZpFVIu.png)
接下來就可以看到畫面囉~
---
## Advanced
### 安裝 ROS
[官網安裝說明](http://wiki.ros.org/melodic/Installation/Ubuntu)
Ver: ros-melodic-desktop-full
```bash=
sudo sh -c 'echo "deb http://packages.ros.org/ros/ubuntu $(lsb_release -sc) main" > /etc/apt/sources.list.d/ros-latest.list'
sudo apt-key adv --keyserver 'hkp://keyserver.ubuntu.com:80' --recv-key C1CF6E31E6BADE8868B172B4F42ED6FBAB17C654
sudo apt update
sudo apt install ros-melodic-desktop-full
apt search ros-melodic
echo "source /opt/ros/melodic/setup.bash" >> ~/.bashrc
source ~/.bashrc
sudo apt install python-rosdep python-rosinstall python-rosinstall-generator python-wstool build-essential
sudo apt install python-rosdep
sudo rosdep init
rosdep update
```
### 創建 ROS workspace
``` = bash
$ cd
$ mkdir -p catkin_ws/src
$ cd catkin_ws
$ catkin_make -DPYTHON_EXECUTABLE=/usr/bin/python3
```
#### 接下來就可以下載或創建package到/catkin_ws/src底下
:::warning
在安裝或創建任何的ROS套件後一定要執行
``catkin_make``
:::
### 建立 ROS Package
```
$ catkin_create_pkg <package_name> [depend1] [depend2] [depend3]
```
```
$ cd ~/catkin_ws/src
$ catkin_create_pkg test
```
### Troubleshooting
#### 找不到ROS套件
##### 在終端機輸入以下指令後重開終端機
`source ~/.bashrc`
`source ~/catkin_ws/devel/setup.bash`
#### rosrun 找不到 node
利用 ```chmod +x node_name``` 將node的檔案改為可執行檔
#### can't find 'rospkg'
`$ pip3 install rospkg`
#### can't find 'catkin_pkg'
`$ pip3 install catkin_pkg`
#### can't find 'em'
`$ pip3 install empy`
#### can't find 'yaml'
`$ pip3 install pyyaml`
## Reference
[ROS自學筆記](https://charlyhuangrostutorial.wordpress.com/ros-%E8%87%AA%E5%AD%B8%E7%AD%86%E8%A8%98/)
[ROS Wiki rostopic](http://wiki.ros.org/rostopic)
[ROS Wiki publisher_and_subscriber](http://wiki.ros.org/ROS/Tutorials/WritingPublisherSubscriber%28python%29#rospy_tutorials.2FTutorials.2FWritingPublisherSubscriber.CA-c82832e0d612370fe9886563f0b7f5433f6caee1_1)
[aws amazon](https://docs.aws.amazon.com/zh_tw/robomaker/latest/dg/simulation-tools-rviz.html)