Dockerを使用してPepperをROSで動かす手順


%docker-machine create --driver virtualbox pepperROS
Creating VirtualBox VM...
Creating SSH key...
Starting VirtualBox VM...
Starting VM...
To see how to connect Docker to this machine, run: docker-machine env pepperROS
docker-machine create --driver virtualbox pepperROS

%VBoxManage list vms
"b2d" {95626e5b-b738-4106-93da-e9344b15a37f}
"ubuntu" {b362125e-83eb-4b8d-b3c3-0a5f26da7543}
"pepperROS" {6b87a8a4-f251-4c63-9c82-d5a68ba621d8}

%docker-machine start pepperROS ruby:[2.2.2]
Started machines may have new IP addresses. You may need to re-run the `docker-machine env` command.

%docker-machine env pepperROS ruby:[2.2.2]
export DOCKER_TLS_VERIFY="1"
export DOCKER_HOST="tcp://192.168.99.100:2376"
export DOCKER_CERT_PATH="/Users/outannexway/.docker/machine/machines/pepperROS"
export DOCKER_MACHINE_NAME="pepperROS"
# Run this command to configure your shell:
# eval "$(docker-machine env pepperROS)"

outannexway@MacBook-Pro ~
%eval "$(docker-machine env pepperROS)"

%docker images ruby:[2.2.2]
Error response from daemon: client is newer than server (client API version: 1.22, server API version: 1.21)


%dm upgrade pepperROS ruby:[2.2.2]
Stopping machine to do the upgrade...
Upgrading machine pepperROS...
Get https://api.github.com/repos/boot2docker/boot2docker/releases: dial tcp: i/o timeout


%dm start pepperROS ruby:[2.2.2]
Starting VM...
Started machines may have new IP addresses. You may need to re-run the `docker-machine env` command.

%eval "$(docker-machine env pepperROS)"

%docker images ruby:[2.2.2]
Error response from daemon: client is newer than server (client API version: 1.22, server API version: 1.21)


%b update ruby:[2.2.2]
error: unable to read askpass response from 'false'
fatal: could not read Username for 'https://github.com': terminal prompts disabled
Error: Fetching /usr/local/Library/Taps/nviennot/homebrew-tmate failed!

DNSなんちゃらの問題らしい。
wifiネットワークを別のwifiに変更してみた

%dm upgrade pepperROS
Stopping machine to do the upgrade...
Upgrading machine pepperROS...
Downloading https://github.com/boot2docker/boot2docker/releases/download/v1.11.0-rc2/boot2docker.iso to /Users/outannexway/.docker/machine/cache/boot2docker.iso...
Starting machine back up...
Starting VM...

%eval "$(docker-machine env pepperROS)"

%docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES

%docker images
REPOSITORY TAG IMAGE ID CREATED SIZE

%docker pull ykoga/pepper-ros-handson ⇒ubuntu+ROS+pepper用ライブラリ?
Using default tag: latest
latest: Pulling from ykoga/pepper-ros-handson

Dockerfileの中身:

Dockerfile
FROM osrf/ros:indigo-desktop

RUN apt-get update && apt-get install -q -y \
ros-indigo-pepper-robot \  ⇒ROSにpepper接続用のライブラリでしょうか?
ros-indigo-pepper-bringup \
ros-indigo-pepper-description \
ros-indigo-naoqi-pose \
ros-indigo-find-object-2d \
ros-indigo-keyboard \
tmux \
terminator \
nano \
emacs \
gedit \
&& rm -rf /var/lib/apt/lists/*

WORKDIR /root

RUN mkdir naoqi-sdk/
RUN mkdir pynaoqi/

ENV PYTHONPATH $PYTHONPATH:/root/pynaoqi/

RUN echo "source /opt/ros/indigo/setup.bash" >> /root/.bashrc

RUN mkdir -p catkin_ws/src
RUN /bin/bash -c '. /opt/ros/indigo/setup.bash; catkin_init_workspace /root/catkin_ws/src'
環境設定ファイルのロードファイルにはROS_ROOT、ROS_PACKAGE_PATHな どの環境変数が定義されている。
新規作成した/root/catkin_ws/srcの配下でcatkin_init_workspaceのコマンドを実行する。

RUN /bin/bash -c 'git clone https://github.com/ykoga-kyutech/pepper_ros_handson.git /root/catkin_ws/src/pepper_ros_handson'
/root/catkin_ws/src/pepper_ros_handsoの配下にgit cloneを実施して、handsonで必要なファイルを取ってくる。

RUN /bin/bash -c '. /opt/ros/indigo/setup.bash; cd /root/catkin_ws; catkin_make'
RUN echo "source /root/catkin_ws/devel/setup.bash" >> /root/.bashrc
⇒root@pepper_robot:~/catkin_ws/devel# cat setup.bash
CATKIN_SHELL=bash
# source setup.sh from same directory as this file
_CATKIN_SETUP_DIR=$(builtin cd "`dirname "${BASH_SOURCE[0]}"`" > /dev/null && pwd)
. "$_CATKIN_SETUP_DIR/setup.sh"


RUN echo "cd /root/catkin_ws/src/pepper_ros_handson; git pull origin master; cd" >> /root/handson_update.sh
⇒/rootの配下にhandson_update.shというファイルを作成

root@pepper_robot:~# apt list | grep -e pepper -e naoqi
ros-indigo-naoqi-bridge-msgs/now 0.0.5-0trusty-20160110-090135-0800 amd64 [installed,local]
ros-indigo-naoqi-driver/now 0.5.7-0trusty-20160203-170424-0800 amd64 [installed,local]
ros-indigo-naoqi-driver-py/now 0.5.3-0trusty-20160111-111509-0800 amd64 [installed,local]
ros-indigo-naoqi-libqi/now 2.3.0-1trusty-20160109-140942-0800 amd64 [installed,local]
ros-indigo-naoqi-libqicore/now 2.3.1-2trusty-20160109-142432-0800 amd64 [installed,local]
ros-indigo-naoqi-pose/now 0.5.3-0trusty-20160111-111357-0800 amd64 [installed,local]
ros-indigo-naoqi-sensors-py/now 0.5.3-0trusty-20160122-032003-0800 amd64 [installed,local]
ros-indigo-pepper-bringup/now 0.1.7-0trusty-20160203-185926-0800 amd64 [installed,local]
ros-indigo-pepper-description/now 0.1.7-0trusty-20160111-165423-0800 amd64 [installed,local]
ros-indigo-pepper-robot/now 0.1.7-0trusty-20160203-191535-0800 amd64 [installed,local]
ros-indigo-pepper-sensors-py/now 0.1.7-0trusty-20160122-053304-0800 amd64 [installed,local]



  • Dockerコンテナ内でGUIを表示できるようにするためのツールのインストール
    こちらのインストーラを使ってQuartzインストールします。→すでにインストールされている
  • インストール後、一度ログアウトしてログインしなおしてください。その後、socatをインストールします。
socatインストール
brew install socat

%brew install socat ruby:[2.2.2]
==> Downloading https://homebrew.bintray.com/bottles/socat-1.7.3.1.el_capitan.bottle.tar.gz
######################################################################## 100.0%
==> Pouring socat-1.7.3.1.el_capitan.bottle.tar.gz


動作確認

コンテナを起動
# ターミナル1
# GUI表示のために必要
socat TCP-LISTEN:6000,reuseaddr,fork UNIX-CLIENT:\"$DISPLAY\"

# ターミナル2
# コンテナ起動
# DISDPLAY=192.168.99.1:0には、ifconfigで調べたvbox0のIPアドレスを入力する
⇒MACの方でifconfigを実行してもvbox0は表示されないけど? 
# --volume 以下には、保存したNaoqi-SDKのフォルダの絶対パスを入力する(Python,C++両方)。以下はホームディレクトリに置いた例
docker run -it --rm --name pepper_robot --hostname pepper_robot --env ROS_HOSTNAME=pepper_robot --env DISPLAY=192.168.99.1:0 --volume="$HOME/workspace/naoqi/pynaoqi-python2.7-2.4.2.26-linux64/:/root/pynaoqi" --volume="$HOME/workspace/naoqi/naoqi-sdk-2.4.2.26-linux64:/root/naoqi-sdk" ykoga/pepper-ros-handson terminator
→sdkのフォルダがdocker containerにmountされること。


※eval "$(docker-machine env pepperROS)" 実行したターミナルでdocker runを実行
%docker run -it --rm --name pepper_robot --hostname pepper_robot --env ROS_HOSTNAME=pepper_robot --env DISPLAY=192.168.99.1:0 --volume="$HOME/workspace/naoqi/pynaoqi-python2.7-2.4.2.26-linux64/:/root/pynaoqi" --volume="$HOME/workspace/naoqi/naoqi-sdk-2.4.2.26-linux64:/root/naoqi-sdk" ykoga/pepper-ros-handson terminator
ConfigBase::load: Unable to open /root/.config/terminator/config ([Errno 2] No such file or directory: '/root/.config/terminator/config')
/usr/share/terminator/terminatorlib/terminator.py:87: Warning: Attempt to add property GnomeProgram::sm-connect after class was initialised
self.gnome_program = gnome.init(APP_NAME, APP_VERSION)
/usr/share/terminator/terminatorlib/terminator.py:87: Warning: Attempt to add property GnomeProgram::show-crash-dialog after class was initialised
self.gnome_program = gnome.init(APP_NAME, APP_VERSION)
/usr/share/terminator/terminatorlib/terminator.py:87: Warning: Attempt to add property GnomeProgram::display after class was initialised
self.gnome_program = gnome.init(APP_NAME, APP_VERSION)
/usr/share/terminator/terminatorlib/terminator.py:87: Warning: Attempt to add property GnomeProgram::default-icon after class was initialised
self.gnome_program = gnome.init(APP_NAME, APP_VERSION)


[Mac] 5. PepperをROSで動かす

ではいよいよPepperをROSで動かしてみましょう
コンテナ内でPepperを起動する# ターミナル1
roscore

# ターミナル2
roslaunch pepper_bringup pepper_full.launch nao_ip:=PepperのIPアドレス nao_port:=9559 network_interface:=eth0

roslaunch pepper_bringup pepper_full.launch nao_ip:=192.168.11.5 nao_port:=9559 network_interface:=eth0
rosrunによりノードを起動できますが,幾つものノードを立ち上げる際には手間となります.
このような手間を解決するものとしてroslaunchが用意されています.



roslaunch pepper_bringup pepper_full.launch nao_ip:=192.168.3.73 nao_port:=9559 network_interface:=eth0
root@pepper_robot:~/catkin_ws# find / | grep pepper_full.launch
/opt/ros/indigo/share/pepper_bringup/launch/pepper_full.launch

root@pepper_robot:/opt/ros/indigo/share# ls -al | grep pepper
drwxr-xr-x 5 root root 4096 Mar 24 01:46 pepper_bringup
drwxr-xr-x 6 root root 4096 Mar 24 01:46 pepper_description
drwxr-xr-x 2 root root 4096 Mar 24 01:46 pepper_robot
drwxr-xr-x 4 root root 4096 Mar 24 01:46 pepper_sensors_py

root@pepper_robot:/opt/ros/indigo/share/pepper_bringup/launch# cat pepper_full.launch
network_interface" default="eth0" />
nao_ip)" />
nao_port)" />

root@pepper_robot:~# rosnode list
//pepper_robot
/pepper_robot/pose/pose_controller
/pepper_robot/pose/pose_manager
/rosout

root@pepper_robot:~# rostopic list
/cmd_vel
/diagnostics
/joint_angles
/joint_states
/move_base_simple/goal
/pepper_robot/audio
/pepper_robot/bumper
/pepper_robot/camera/bottom/camera_info
/pepper_robot/camera/bottom/image_raw
/pepper_robot/camera/depth/camera_info
/pepper_robot/camera/depth/image_raw
/pepper_robot/camera/front/camera_info
/pepper_robot/camera/front/image_raw
/pepper_robot/camera/ir/camera_info
/pepper_robot/camera/ir/image_raw
/pepper_robot/imu/base
/pepper_robot/imu/torso
/pepper_robot/info
/pepper_robot/laser
/pepper_robot/pose/body_pose/cancel
/pepper_robot/pose/body_pose/feedback
/pepper_robot/pose/body_pose/goal
/pepper_robot/pose/body_pose/result
/pepper_robot/pose/body_pose/status
/pepper_robot/pose/body_pose_naoqi/cancel
/pepper_robot/pose/body_pose_naoqi/feedback
/pepper_robot/pose/body_pose_naoqi/goal
/pepper_robot/pose/body_pose_naoqi/result
/pepper_robot/pose/body_pose_naoqi/status
/pepper_robot/pose/joint_angles
/pepper_robot/pose/joint_angles_action/cancel
/pepper_robot/pose/joint_angles_action/feedback
/pepper_robot/pose/joint_angles_action/goal
/pepper_robot/pose/joint_angles_action/result
/pepper_robot/pose/joint_angles_action/status
/pepper_robot/pose/joint_stiffness
/pepper_robot/pose/joint_stiffness_trajectory/cancel
/pepper_robot/pose/joint_stiffness_trajectory/feedback
/pepper_robot/pose/joint_stiffness_trajectory/goal
/pepper_robot/pose/joint_stiffness_trajectory/result
/pepper_robot/pose/joint_stiffness_trajectory/status
/pepper_robot/pose/joint_trajectory/cancel
/pepper_robot/pose/joint_trajectory/feedback
/pepper_robot/pose/joint_trajectory/goal
/pepper_robot/pose/joint_trajectory/result
/pepper_robot/pose/joint_trajectory/status
/pepper_robot/sonar/back
/pepper_robot/sonar/front
/pepper_robot/tactile_touch
/rosout
/rosout_agg
/speech
/tf


# 発話

rostopic pub --rate=0.5 /speech std_msgs/String "わーい、久々のテックサークルだー"



# 移動

rostopic pub /cmd_vel geometry_msgs/Twist '{linear: {x: 0.0, y: 0.0, z: 0.0}, angular: {x: 0.0,y: 0.0,z: 0.2}}'

・Pepperノードからは様々なセンサデータの出 、 アクションコマンドの を受け付けている
・ROSのコマンドを使ってセンサデータを表 したり、 Pepperにアクションを取らせることが可能


画像認 パッケージの 使用
root@pepper_robot:/opt/ros/indigo/share# ls -al | grep find
drwxr-xr-x 5 root root 4096 Mar 24 01:46 find_object_2d

# find_object_2dパッケージの中にある、find object 2dノードを起動する
# image:=以下に指定したトピック名を入力画像とする

# 画像学習、認識を行うノードを起動
rosrun find_object_2d find_object_2d image:=/pepper_robot/camera/front/image_raw
root@pepper_robot:/opt/ros/indigo/share/find_object_2d/launch# cat find_object_2d.launch
find_object_2d" pkg="find_object_2d" type="find_object_2d" output="screen">

# 認識結果を表示
rostopic echo /objects
data: [1.0, 131.0, 158.0, 2.3312923908233643, 1.8839465379714966, 0.008858189918100834, -0.3924359977245331, 1.5002127885818481, 5.590323416981846e-05, 18.928314208984375, -7.218011856079102, 1.0]

表示後、認識結果の先頭にオブジェクトID(整数)があることを確認
/objectsの形式: [オブジェクトID1, オブジェクトの幅、オブジェクトの高さ、H11, H12, H13, H21, ....., H33, オブジェクトID2, ...]
・H##は3x3のホモグラフィー
⇒学習したデータはどこで保存されるか?
find_object_2dノードのどこかで保存されていないか? 
ファイル・システムで保存されていないか?
実際のアプリを開発する時にはこのデータをDBに保存するのか?
⇒png画像だけ保存すればできそうです。
find_object_2dのツールで学習した画像をファイル・システムに保存
使う時は、保存のした画像をfind_object_2dツールに読み込むだけだそうですね。

手動で~/dictionaryに学習した画像を保存した。
root@pepper_robot:~/dictionary# ls -al
-rw-r--r-- 1 root root 21250 Apr 12 18:51 1.png
-rw-r--r-- 1 root root 48685 Apr 12 19:20 object_2.png


root@pepper_robot:~# rosnode info /find_object_2d
--------------------------------------------------------------------------------
Node [/find_object_2d]
Publications:
* /tf [tf2_msgs/TFMessage]
* /rosout [rosgraph_msgs/Log]
* /objects [std_msgs/Float32MultiArray]
* /objectsStamped [find_object_2d/ObjectsStamped]

Subscriptions:
* /pepper_robot/camera/front/image_raw [sensor_msgs/Image]

Services:
* /find_object_2d/get_loggers
* /find_object_2d/set_logger_level


contacting node http://pepper_robot:40054/ ...
Pid: 1293
Connections:
* topic: /rosout
* to: /rosout
* direction: outbound
* transport: TCPROS
* topic: /pepper_robot/camera/front/image_raw
* to: http://172.17.0.2:42497/
* direction: inbound
* transport: TCPROS


/* ----------------------
2. Pythonコード作成
------------------------- */

# パッケージ作成
cd ~/catkin_ws/src
catkin_create_pkg create_speech rospy std_msgs

# Python雛形コードのダウンロードとパッケージのビルド
cd create_speech
mkdir scripts && cd scripts
curl -o create_speech.py https://raw.githubusercontent.com/ykoga-kyutech/pepper_ros_handson/master/scripts/create_speech_template.py
chmod +x create_speech.py
cd ~/catkin_ws && catkin_make
source ~/catkin_ws/devel/setup.bash

# create_speechノードの実行
rosrun create_speech create_speech.py

# Pythonコードの編集
emacs ~/catkin_ws/src/create_speech/scripts/create_speech.py

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import rospy
from std_msgs.msg import String
from std_msgs.msg import Float32MultiArray

class CreateSpeech:

def __init__(self):

# init node
rospy.init_node('create_speech')

# Publisher
self.pub = rospy.Publisher('speech', String, queue_size=1)

# Subscriber
rospy.Subscriber('objects', Float32MultiArray, self.callback)

# object dictionary
self.known_objects = {1:"オウタン", 2:"ペッパーのおしらせ"}
⇒実際のアプリ開発ではこのobject dictionaryはDBで管理するのでしょうか?


# recognized object
self.obj_name = ''

def callback(self, msg):

if len(msg.data):
rospy.loginfo('object found.')

# get object ID
idx = int(msg.data[0])

# if the dictionary includes the object ID
if idx in self.known_objects:
self.obj_name = self.known_objects[idx]
else:
rospy.loginfo('object NOT found.')
self.obj_name = ''

def pub_speech(self):

if self.obj_name != '':
speech_str = self.obj_name + 'だね'
self.pub.publish(speech_str)

def main():

speech = CreateSpeech()

# loop rate [Hz]
r = rospy.Rate(0.3)

while not rospy.is_shutdown():
speech.pub_speech()
r.sleep()

if __name__ == '__main__':
try:
main()
except rospy.ROSInterruptException:
pass

catkin_wsフォルダをMACと同期を取る
docker run -it --rm --name pepper_robot --hostname pepper_robot --env ROS_HOSTNAME=pepper_robot --env DISPLAY=192.168.99.1:0 --volume="$HOME/workspace/pepper/catkin_ws:/root/catkin_ws" --volume="$HOME/workspace/pepper/naoqi/pynaoqi-python2.7-2.4.2.26-linux64/:/root/pynaoqi" --volume="$HOME/workspace/pepper/naoqi/naoqi-sdk-2.4.2.26-linux64:/root/naoqi-sdk" ykoga/pepper-ros-handson terminator

rootフォルダ全体をMACと同期を取る。
docker run -it --rm --name pepper_robot --hostname pepper_robot --env ROS_HOSTNAME=pepper_robot --env DISPLAY=192.168.99.1:0 --volume="$HOME/workspace/pepper/ros/root:/root" -- ykoga/pepper-ros-handson terminator
⇒sdkファイルは~/workspace/pepper/ros/rootの配下に置く。