ちょっといきぬき

vimとかpythonとかロボットとかMLとか環境構築とかの興味ある技術のことを書きたいだけの人生だった。

NAO/PepperでもPyAudioが使いたい!

なんとなく使えるようにしたかった

NAO/Pepper上で音声録音/再生をしたい時、通常はNAOqi標準APIのALAudioDeviceを使います。例えばChoregrapheのRecord Soundボックスとかが使ってる。

ただ、なんとなくNAO/Pepper上でPyAudioを使いたくなったため、手順とハマりポイント備忘録としてブログに残します。

(世の中のPythonサンプルコードそのまま使いたいとかなんとか)

環境

  • NAO/Pepper実機
  • OpenNAO OS
  • VirtualBox
  • NAOqiと同じVersionのChoregraphe

注意事項

NAO実機でのみ動作確認してます。 同じNAOqiプラットフォームのPepperでも多分動くと思います。

また、設計思想から実機上でコマンド打ったり実機の環境を変更したりしないのと、1つのプロジェクトをインストールするだけで簡潔させる縛り。

個人ブログなので間違いも多々あります。 その時はご指摘、ご指導頂けますと大変ありがたいです。

大まかな手順

  1. 開発環境、VMの準備
  2. VM上で必要モジュール作成と移行
  3. プロジェクトの作成
  4. 共有ライブラリのリンクをどうするか

1. 開発環境、VMの用意

ここ最近(?)のAldebaran RoboticsとSoftbank Roboticsの合併に伴う現象か不明ですが、インストーラーのダウンロードサイトが分散してます。(2017/03/03現在)

homepage | SoftBank Robotics Community
とか
Pepper Developer Portal

Choregrapheはどちらからダウンロードしても支障は無いと思いますが、OpenNAO OSは前記のサイトにしか無いためそちらからダウンロードしたいところですが、ダウンロードリンクにたどり着くまでが大変分かりづらいので以下をどうぞ。

https://community.ald.softbankrobotics.com/en/resources/software/language/en-gb

ただし

You are not authorized to access this page.

って怒られるのでSign Inからアカウント作ってログインして入手して下さい。

入手し終えたらChoregraphe、OpenNAO OS、VirtualBoxをそれぞれインストールします。

2. VM上で必要モジュール作成と移行

OpenNAO OS上でコンパイルしたモジュールはそのままNAO/Pepper上で動くみたいなので、PyAudioとその依存モジュールportaudioをインストールします。

やってることはこのあたりを参考にしてます。

Developing a project for NAO using third-party software — Aldebaran 2.1.4.13 documentation

VirtualBoxからOpenNAO OSを起動し、コンソールを開くとログインユーザーとパスワードを問われるので以下入力します。

ユーザー名:nao
パスワード:nao

SSHを使いたい方は以下コマンドでもアクセス出来ます。
クリップボードのコピペなんかが何故だか上手く機能しないのでSSHの方が良いと思います。

HOST $ ssh -p 2222 nao@localhost

emergeコマンドでportaudioをインストールします

VM $ su
Password: root
VM # emerge portaudio
VM # exit

パッケージをインストールすると/home/nao/opennao-distro/packagesに配置されます。

VM $ tree /home/nao/opennao-distro/packages
opennao-distro/packages/
|-- Packages
`-- media-libs
    `-- portaudio-19_pre20071207.tbz2

パッケージの内容は以下コマンドで確認出来ます。

VM $ equery files portaudio

本来はそこの圧縮ファイルを使うべきですが、展開済のパッケージは/usr/libにもあるのでそちらを使います。

VM $ ls /usr/lib | grep libportaudio

PyAudio依存ライブラリのlibportaudio.so.2.0.0とlibportaudio.so.2をホストOSに持ってきます。 ホストOSのターミナルから以下コマンドを入力してダウンロードします。

HOST $ scp -r -P 2222 nao@localhost:/home/nao/libportaudio.so.2.0.0 .
HOST $ scp -r -P 2222 nao@localhost:/home/nao/libportaudio.so.2 .

ターミナルの無い方はフリーのSFTPソフトでもダウンロード出来ます。

サーバー:localhost
ポート:2222
ユーザー名:nao
パスワード:nao

また、pipコマンドでPyAudioもインストールします。

VM $ su
VM # pip install pyaudio
VM # exit

pipでインストールしたモジュールは/usr/lib/python2.7/site-packagesにあります。必要パッケージをホストOSにダウンロードします。

HOST $ scp -r -P 2222 nao@localhost:/usr/lib/python2.7/site-packages/_portaudio.so .
HOST $ scp -r -P 2222 nao@localhost:/usr/lib/python2.7/site-packages/pyaudio.py .

3. プロジェクトの作成

Choregrapheかqibuildでアプリパッケージが作れますが、後者は素でXML書くのが大変なのでChoregrapheで作ったプロジェクト内にモジュール突っ込みます。

sample-project/
|-- lib
|   |-- libportaudio.so.2.0.0
|   |-- libportaudio.so.2
|   |-- _portaudio.so
|   `-- pyaudio.py
|
`-- behavior_1
    `-- behavior.xar

あとはsys.path.append()するなりPYTHONPATH通してimport pyaudioと出来る…と思いきや。

4. 共有ライブラリのリンクをどうするか

実際にプロジェクトを実行するとエラーが出ます。それもそのはず、 pyaudio依存ライブラリの_portaudio.soがlibportaudio.so.2を正しくリンクできていません。

NAO $ ldd _portaudio.so
ldd: warning: you do not have execution permission for `./_portaudio.so'
    linux-gate.so.1 =>  (0xffffe000)
    libportaudio.so.2 => not found
    libpython2.7.so.1.0 => /usr/lib/libpython2.7.so.1.0 (0xb75b5000)
    libpthread.so.0 => /lib/libpthread.so.0 (0xb759b000)
    libc.so.6 => /lib/libc.so.6 (0xb743b000)
    libdl.so.2 => /lib/libdl.so.2 (0xb7436000)
    libutil.so.1 => /lib/libutil.so.1 (0xb7432000)
    libm.so.6 => /lib/libm.so.6 (0xb740c000)
    /lib/ld-linux.so.2 (0xb7747000)

これを直すには、一般的には

① LD_LIBRARY_PATHにライブラリまでのパスを教えるか、

② /etc/ld.so.confに直接パスを書き込むか

③ os.environ[‘LD_LIBRARY_PATH’] = ‘/path/to/lib’ # する

方法がありますが、①②は注意事項にある通り直接exportコマンドなどは使いたくない、実機の環境を変更したくない。 1プロジェクトのインストールだけで簡潔させたい。

Pythonスクリプトからsubprocessなどでexportをしても、シェル変数は親プロセスに引き継がれないし、 LD_LIBRARY_PATHの評価はPython実行前にされるので③もダメ。

そこでどうするか悩んでいたさなか、以下の記事を見つけて参考にしたら行けた。

LD_LIBRARY_PATHとPythonとPaiza.io問題あるいはpaiza.ioでmrubyを動かしhttp2通信する - Qiita

import ctypes
dummy = ctypes.CDLL("/path/to/lib/libportaudio.so.2")

import pyaudio

無駄な努力かもしれないけど無事pyaudioがインポート出来たので良しとしよう。

※3/14追記
結局今はNAOqiのALAudioDevice APIを使ってる