はじめに
Dockerの勉強がしたかったので、ラズパイでDockerとROSを使ってみることにしました。ラズパイにROSをインストールする方法としては、Raspbian Jessie を使う方法や、ubuntu MATE を使う方法がありますが、ここではRaspbian StretchとDockerを使います。
環境構築
Raspbian Stretchのインストール
Installing operating system images を参考に、SDカードにRaspbianをインストールします。
- Raspbian Stretch with desktopをダウンロードします。RaspberryPi公式 からダウンロードするとかなり時間がかかりますが、JAISTのミラー からダウンロードすると早く終わります。(参考)
- ダウンロードしたzipファイルを解凍してSDカードに書き込みます。
Dockerのインストール
ラズパイを起動し、Get Docker CE for Debian にしたがってDocker CEをインストールします。(CEはCommunity Editionで無償版です。)
-
通常はリポジトリからインストールするそうですが、Raspbianにはまだ対応していないのでcurlでインストールスクリプトを持ってきてインストールするそうです。
$ curl -fsSL https://get.docker.com -o get-docker.sh $ sudo sh get-docker.sh
-
インストールが終わったら、sudoなしでdockerを使用できるように、dockerグループに現在のユーザを追加します。Raspbianの初期設定時のユーザ名はpiなので、次のコマンドを実行します。(ログアウト/ログイン後にusermodの変更が反映されるので、ここで再起動しておきます。)
$ sudo usermod -aG docker pi $ reboot
-
dockerが正常に動作するか確認するため、Hello Worldを実行します。
$ docker run hello-world
一瞬、「unable to find image 'hello-world:latest' locally」と表示されますが、ローカルにないDockerイメージからコンテナを作成しようとしたためです。ローカルにないイメージは自動的にダウンロードされます。
「Hello from Docker!」が表示されました。
ROSを使ってみる
ROSイメージの利用
Getting started with ROS and Docker を参考にROSを動かしてみます。
-
docker pull
コマンドでDockerイメージを持ってきます。ROSのDockerイメージはDockerHubに登録されています。
また、イメージ名の後ろにコロンとタグをつけることでROSのディストリビューションなどを指定することができます。今回はKineticを使ってみたいと思います。$ docker pull ros:kinetic
-
ダウンロードが終わったら、
docker run
コマンドでイメージからコンテナを起動します。-it
オプションをつけると、起動と同時にコンテナ内に入ります。$ docker run -it ros:kinetic
-
コンテナ内で、
roscore
コマンドを実行してROSのmasterを起動します。roscore
-
先ほど起動したコンテナの名前を取得します(
docker run
を実行するとき--name
オプションでコンテナ名を指定しないと適当な名前に設定されるそうです)。新しいターミナルを立ち上げてdocker ps
コマンドを実行すれば確認できます(-l
オプションをつけると最後に起動したコンテナのみを表示します)。$ docker ps -l
-
コンテナ名が分かったので、新しいターミナルからコンテナ内に入ります。
docker exec
は指定したコマンドをコンテナ内で実行するコマンドですが、-it
オプションをつけてbash
を実行することで、コンテナ内に入ることができます。$ docker exec -it jolly_wing bash
-
入った直後に
rostopic list
を実行しようとすると、"bash: rostopic: command not found"のエラーになるので、先に以下のコマンドでROSの環境をセットアップします(もしくはsource /ros_entrypoint.sh
でもセットアップできるようです)。source /opt/ros/kinetic/setup.bash
こうしてから
rostopic list
を実行すると、次のようにトピックのリストが表示されます。 -
コンテナから抜けるには、
exit
コマンドを実行します。exit
ちなみに、
docker exec
した方のターミナルでexit
コマンドを実行するとコンテナから出た後もコンテナは動いたままです。一方、docker run
でコンテナを起動したターミナルでexit
コマンドを実行すると、コンテナも停止します。 -
docker rm
コマンドを使えばコンテナを削除できます。まず、現在のコンテナを確認します。docker ps
コマンドに-a
オプションをつけると停止したコンテナも含めてすべてのコンテナの一覧が表示されます。$ docker ps -a
$ docker rm jolly_wing
コンテナが削除されました。
ワークスペースの作成
コンテナ内にROSのワークスペース(catkin_ws)を作り自作のROSパッケージを置きたいところですが、Dockerfile のベストプラクティスによるとコンテナはいつでも廃棄できるようにするべきらしく、ソースコードなどはコンテナ内に置かないようです。
Best practices for getting code into a containerを読む限り、外部のソースコードをコンテナ内に取り込む方法はいくつかあるようですが、とりあえずdocker run
を実行する際に-v
オプションを使うことで、ホスト側のディレクトリをコンテナと共有できるそうです。
Docker HubのDeployment suggestionsにも、-v
オプションを使ってROSのログファイルをホスト側に残す方法が記載されていますので、これを参考にホスト側とコンテナ側で共有するワークスペースを作成します。
-
ホスト側で~/.rosディレクトリと~/catkin_ws/srcディレクトリを作ります。
$ mkdir ~/.ros $ mkdir -p ~/catkin_ws/src
-
次のコマンドでコンテナを起動します。
-v
の後に続く/home/pi/catkin_ws/
がホスト側、:
の後に続く/root/catkin_ws/```がコンテナ側のワークスペースのディレクトリです。$ docker run -it -v "/home/pi/.ros/:/root/.ros/" -v "/home/pi/catkin_ws/:/root/catkin_ws/" ros:kinetic
-
コンテナの中に入ったら、Creating a ROS Packageを参考にチュートリアル用のROSパッケージを作ります。
cd ~/catkin_ws/src catkin_create_pkg beginner_tutorials std_msgs rospy roscpp
-
パッケージを作成できたので、
catkin_make
でワークスペースをビルドします。cd ~/catkin_ws catkin_make
-
コンテナから抜けて、ホスト側のワークスペースにもROSパッケージとbuildディレクトリが追加されているか確認します。
これで、ホスト側のワークスペースにソースファイルを追加して編集すれば、再度
docker run
を実行したときに、それをコンテナに取り込むことができます。
おわりに
なんとかラズパイとDockerでROSが動くようにできました。少し手間がかかりますが、DockerfileからDockerイメージを作れるようになればいろいろ便利になりそうです。