Virtualbox内のROSからGoPiGoを動かす

## 前置き

大学の研究室でGoPiGoをrosで動かしてみようということになりました。
PCを一台用意し、その上にrosの環境を整えてやってみるという話だったのですが、
その前に自分のPC上から動かしてみようということで試してみました。
やっと動いたので、自分が実際にやった部分の流れをメモっていきたいと思います。

## 前提

### PC側の設定

* ホストOS ： Windows10
* 仮想マシン ： Virtualbox
* ゲストOS ： ubuntu 16.04

### GoPiGo側の設定
* GoPiGo ： GoPiGo3
* RaspberryPi ：Raspberry Pi 3 model B
* OS ： ubuntu mate 16.04

ゲストOSにはubuntu16.04がはいっており、GoPiGoにはubuntu mate16.04 が入っていることを前提とします。 

環境構築は以下のページを参考にしました。  

PC側の設定
[【初心者でもわかる】VirtualBoxインストール方法を詳しく！](https://eng-entrance.com/virtualbox-install)
[VirtualBoxにUbuntu 16.04をインストールする前にやること](https://sicklylife.hatenablog.com/entry/2016/11/28/210512)  

GoPiGo側の設定
[第48回「ラズベリーパイにUbuntu MATEをインストール！」](https://deviceplus.jp/hobby/raspberrypi_entry_048/)
[ROSでgopigo3を走らせる](https://qiita.com/cut0ter/items/0326f5dee89456e47001)

## 作業の流れ

1. Virtualboxのネットワークアダプタを「ブリッジ接続」にする。  
   ※Windowsファイヤーウォールについても
1. ゲストOSに「ROS」を入れる
1. GoPiGoに「ROS」を入れる
1. プログラムを書く
1. プログラムを実行

## 1. Virtualboxのネットワークアダプタを「ブリッジ接続」にする。

GoPiGoを遠隔操作するためには、Virtualbox内の環境をGoPiGoと同じネットワークに接続する必要があります。
ブリッジ接続にすると、ホストマシンと同じネットワークに接続できるようになるため、その設定にします。

※以下のサイトを参考にしました。
[【いまさら聞けない！エンジニアの基本シリーズ】 第2回 VirtualBox基本動作編](https://www.adoc.co.jp/blog/e000283.html)

※無線で通信を行うため、無線通信のモジュールをブリッジに設定します。

<div style="text-align: center;">
  <img src="https://qiita-image-store.s3.amazonaws.com/0/270556/0f7d336a-3761-872a-2b80-97abcbaf1aa0.png" width="600" height="auto">
</div>

## ☆Windowsのファイやウォールが邪魔をする。

環境によっては、Windows内のファイやウォールが理由でつながらない可能性があります。  
自分の場合は、`Symantec`が起動していたため、GoPiGoとの相互通信ができませんでした。
そのため、GoPiGoと通信する時のみ、Symantecを無効にします。  

※GoPiGoの通信が終わったら、Symantecを有効に戻してください。
※常に通信できるようにしたい場合は別途ファイやウォールの設定をいじくってみてください。

<div style="text-align: center;">
  <img src="https://qiita-image-store.s3.amazonaws.com/0/270556/45a110d4-ce6e-e710-19cb-2ec6bf5bee43.png">
</div>

## 2. ゲストOSに「ROS」を入れる。

Virtualbox内のUbuntuに `ROS Kinetic` を入れる。 

※以下のページを参考にしてインストールしました。
[ROS Kinetic の Ubuntu へのインストール](http://wiki.ros.org/ja/kinetic/Installation/Ubuntu)

### ゲストOS内で実行

    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://ha.pool.sks-keyservers.net:80 --recv-key 421C365BD9FF1F717815A3895523BAEEB01FA116
    sudo apt-get update
    sudo apt-get install ros-kinetic-desktop-full
    sudo rosdep init
    rosdep update
    echo "source /opt/ros/kinetic/setup.bash" >> ~/.bashrc
    source ~/.bashrc
    sudo apt-get install python-rosinstall

## 3. GoPiGoに「ROS」を入れる。

GoPiGo内のUbuntuに `ROS Kinetic` をいれる。
流れはVirtualboxの際とほとんど同じです。

※以下のページを参考にしてインストールしました。  
[ROS Kinetic の Ubuntu へのインストール](http://wiki.ros.org/ja/kinetic/Installation/Ubuntu)
[ROSでgopigo3を走らせる](https://qiita.com/cut0ter/items/0326f5dee89456e47001)

### GoPiGoで実行

`2. ゲストOSに「ROS」を入れる` や、上記の `ROSでgopigo3を走らせる` を参照してください。
※なお、GoPiGo内で実行してください。

## 4. プログラムを作成する。

GoPiGoと、ゲストOS内に、それぞれ必要なプログラムを作成していきます。  

全体の構造としては以下のようになっています。
ゲストOS内でros masterとpublisherを動作させ、GoPiGo内でsubscriberを動作させます。
GoPiGo内のプログラムは、ゲストOS内のros masterを利用して通信するようにする。

<div style="text-align: center;">
  <img src="https://qiita-image-store.s3.amazonaws.com/0/270556/bb14fcfa-9216-6eab-1c70-0fea8390af5a.png" width="500">
</div>

基本的にゲストOS(Publisher)から指示を送り、GoPiGo(Subscriber)がそのデータを受け取り動作するという構成になっています。

### ゲストOS側のプログラム

ゲストOS側では、基本的に移動の指示をGoPiGoに送ります。
※ファイル名は`director.py`とする。 

    # director.py

    #!/usr/bin/env python

    import rospy
    from std_msgs.msg import Float64

    def straight_move_in(dict):
      
      pub = rospy.Publisher('gopigo', Float64, queue_size = 10)
      rospy.init_node('director', anonymous=True)
      pub.publish(dict)

    if __name__ == "__main__":
      #10cmだけGoPiGoを前に進める
      straight_move_in(10)


### GoPiGo側のプログラム

GoPiGo側では、送られてきた値の分だけ前進するようになっています。
※ファイル名は`move_gopigo.py`とする。

    # move_gopigo.py

    #!/usr/bin/env python
    import rospy
    import easygopigo3 as easy
    from std_msgs.msg import Float64

    gpg = easy.EasyGoPiGo3()

    #Subscriberのcallback関数
    #この中でgpgの様々な処理をさせる

    def gopigo_callback(dist):
      #指定したcmだけ前に進む。
      gpg.drive_cm(dist.data, blocking=False)

    def move_gopigo():
      rospy.init_node('gopigo_body', anonymous=True)
      rospy.Subscriber('gopigo', Float64, gopigo_callback)
      rospy.spin()

    if __name__ == '__main__':
      move_gopigo()


## 5. プログラムを実行
`ゲストOS`と`GoPiGo`側でそれぞれ作成したプログラムを実行していく。

### ゲストOS側で `ROS Master` を起動

はじめに、ゲストOS側でROS Masterを実行するため、`roscore`を実行

    roscore

### GoPiGo側のプログラムの実行

GoPiGo側ではまず、ROS masterのIPアドレスを設定する必要があります。

    export ROS_MASTER_URI=http://<ゲストOSのIPアドレス>:11311

また、複数の媒体でする場合は、機体それぞれのIPアドレスを改めて設定してあげる必要がある。

    export ROS_IP=<GoPiGoのIPアドレス>

その後、ゲストOSからの指示を受ける `move_gopigo.py` を実行。

    python move_gopigo.py

### ゲストOS側のプログラムを実行

ゲストOSも同様に自らのIPアドレスを指定

    export ROS_IP=<ゲストOSのIPアドレス>

最後に、GoPiGoに指示を出す `director.py` を実行する。

    python director.py

これでGoPiGo3が動作しました。