WindowsでROSを動かしてみる(その1)
Simple Wiki Based Contents Management System
関心分野 >> WindowsでROSを動かしてみる(その1)

WindowsでROSを動かしてみる(その1)

ROSは、Linuxではインストールも簡単ですし、開発も楽なのですが、eSEATでROSノードをサポートした関係で、Windowsでも動かないか試してみました。
ROSの多くのコマンドやパッケージはPythonで実装されているものがありましたので、中身を確認しました。より簡単化のために ros-melodic-ros-base でインストールしたライブラリを使用しています。
現在のところ、Python版のtalker.pyは動作しているみたいです。

準備

ROSのモジュール群を収集

まずは、ROSのパッケージが必要なのですが、apt-getでインストールすることになっていましたので、Windowsではどうしようもありません。そこで、VirtualBoxにUbuntu-18.04LTSをインストールして、ROS(melodic)をインストールし、PythonのROSノードを動かすために必要なものをコピーしてくることにしました。
ROSのインストール自体は、多くのサイトやこのサイトのページにもやり方やインストールスクリプトがありますので省略します。
ROS(melodic)をインストールできたら、必要ファイルをコピーしていきます。ホームディレクトリの下に、rosというディレクトリを作って集めていきましょう。
 # mkdir -p ~/ros/melodic/lib
 # cd ~/ros/melodic
 # cp -a /opt/ros/melodic/lib/python2.7 lib
 # cp -a /opt/ros/melodic/bin .
 # cp -a /opt/ros/melodic/etc .
 # cp -a /opt/ros/melodic/share .
また、actionlibやmsgsの生成には、libの下の他のパッケージが必要となるはずです。 actionlib, actionlib_msgs, genmsgs, genpyくらいはコピーしておいた方がいいかもしれません。(まだ、未確認です)
上記のモジュールのみでは、rospyのimportで失敗します。これは、ROSの一部のモジュールは、/usr/lib/python2.7/dist-packagesにインストールされているからです。
したがって、下のように必要なモジュールをコピーします。
 # cd ~/ros/melodic/lib/python2.7/dist-packages
 # cp -a /usr/lib/python2.7/dist-packages/ros* .
 # cp -a /usr/lib/python2.7/dist-packages/catkin* .
以上で必要なファイルの収集は完了です。
/ros をUSBメモリか共有フォルダを使って Windows上にコピーしてください。

Windows上での準備

次に、Windows上での準備を行います。
ROSをWindows上で動作させるためには、Python2.7が必要になります。(おそらくPython3.6でも動くとは思いますが)
そこで、Python2.7をオフィシャルサイトからダウンロードしてインストールを行ってください。
Python2.7 は、64ビット版でも32ビット版でも動作するはずですので、Windows x86-64 MSI installerまたはWindows x86 MSI installerのどちらでインストールしてもOKです。
Pythonのインストールが終われば、上で収集したrosのファイル群をWindows上にコピーします。
コピーする場所はどこでもよいと思いますが、Linuxの場合にあわせて C:\optの下にコピーすればよいと思います。
Pythonの追加モジュールのインストール
インストーラでインストールを行ったPythonでは、ROSを動かすために必要なモジュールが不足しています。私が確認したところ、最低でも下のモジュール群が必要です。
  1. PyYaml
  2. pyparsing
  3. defusedxml
  4. gnupg
  5. argparse
  6. python-dateutil
  7. docutils
  8. Crypto
上のライブラリのほとんどは、PyPIを使ってインストールすることができます。しかし、最後のCryptoは、PyPIでインストールを行う場合に、Visual C++ 9.0が必要になりますので、Visual C++ 9.0がない方は、バイナリで配布されているサイトからダウンロードしてインストールしてください。
ROSの環境設定とソースファイルの修正
あとは、ROSを動作させるための環境変数の設定と一部のソースファイルを修正します。
まずは、ソースファイルの修正ですが、 ros\medloic\lib\python2.7\dist-packages\rosgrap\roslogging.py を修正します。本来は、log機能が正しく動作している場合には問題なかったのですが、logが使えない場合には、このファイルでエラーが発生します。
上記のファイルを開いて 69行目に下の一行を入れてください。
   if f is None: raise ValueError
これは、RospyLoggerのfindCallerというメソッド内の処理です。fがNoneの場合には、AttributeErrorが発生するのですが、このメソッドの呼び出し元が、ValueErrorしかキャッチしていませんでした。そのための修正です。しかしながら、roscoreが正常に起動し、rosoutが動作すればおそらく問題は発生しないと思います。上記の修正を加えても、元のROSに問題は与えないはずなので、修正をPullRequestした方がいいかもしれません。
次に、ROSを動作させるために環境変数の設定を行います。
ROS(rospyやrosmaster等)を動作させるには、PYTHONPATH,PATHの設定や最低限ROSのコマンドを起動させるための変数 ROS_HOSTNAME, ROS_MASTER_URI, ROS_PYTHON_LOG_CONFIG_FILEを設定します。本来は、rospkg/environment.py にある変数をすべて設定した方が良いと思いますが、簡単なサンプルと動作確認には、上記の3つの環境変数の設定でOKです。
ROS_HOSTNAMEとROS_MASTETR_URIは、ローカルのPC内でのみROSノードを起動する場合には設定の必要はありません。しかし、さまざまなモジュールや外部の機器を使ったりする場合には結局必要ですので、取り敢えずここで設定します。
ROS_PYTHON_LOG_CONFIG_FILEは、デフォルトだと etc\ros\python_logging.confになりますが、これを指定するとパスの問題や他のモジュールの起動のチェックなども同時に行わなければいけませんので、存在しないファイル名に設定します。
ROSのモジュールでは、ROS_PYTHON_LOG_CONFIG_FILEで設定されたファイルが存在しなければ、ログ機能が使えないということですが、初期起動と動作確認のみでは無視したいと思います。後日、動作できれば再度環境変数の設定を行いたいと思います。
以上を考えて、下のように設定したバッチファイルを C:\opt\ros\melodic\setup.batとして保存します。
set ROS_HOME=%~dp0
set PYTHONPATH=%ROS_HOME%lib\python2.7\dist-packages;%PYTHONPATH%
set PATH_ORG=%PATH%
set PATH=%ROS_HOME%scripts;%PATH%
set ROS_HOSTNAME=localhost
set ROS_MASTER_URI=http://localhost:11311
set ROS_PYTHON_LOG_CONFIG_FILE=no_logconfig
set ROS_ETC_DIR=%ROS_HOME%etc\ros
set ROS_ROOT=%ROS_HOME%share\ros
set ROS_VERSION=1
set ROS_PYTHON_VERSION=2
set ROS_PACKAGE_PATH=%ROS_HOME%share
set ROS_DISTRO=melodic
ここまで設定できれば、Pythonの起動のための環境変数(PATHとPYTHONPATH)の設定も付け加えれば準備完了です。

Windowsでの起動テスト

準備が完了でき来たら、Windows上で動作テストを行います。ここでは、rosのチュートリアルの最初にある talker.py と listener.pyで動作確認を行います。

Python27の設定とsetup.batの読込

まずは、環境変数の設定です。Pythonが C:\Python27にあるとして下記のように設定します。
 > set PYTHON_HOME=C:\Python27
 > set PATH=%PYTHON_HOME%;%PYTHON_HOME%\DLLs;%PYTHON_HOME%\Scripts;%PYTHON_HOME%\Lib;%PYTHON_HOME%\Lib\site-packages\pywin32_system32;%PATH%
 > set PYTHONPATH=%PYTHON_HOME%\Lib;%PYTHON_HOME%\Lib\site-packages;%PYTHONPATH%
 > C:\opt\ros\melodic\setup.bat

rosmasterの起動

現在のROSでは、rosmasterではなくroscoreで起動していますが、roscoreの内部では、必要なPATHやオプションの設定を行い、subprocess関数などで、rosmasterの呼び出しやrosoutの起動などを行っています。
ROSで最低限必要なのは、Masterである rosmaster ですので、ここでは、このプログラムのみを起動させます。
 > start python %ROS_HOME%bin\rosmaster --core -p 11311 -w 3
上記のコマンドを実行するとコマンドプロンプトのウィンドウが表示されてrosmasterが起動します。ウィンドウがすぐに閉じてしまう場合には何らかのエラーが出ているはずですので、上記のコマンドのstartを削除して実行してみるとわかると思います。

rosnode, rostopic, rosmsgの動作確認

ROSを使う時によく使うコマンドとして rosnode, rostopic, rosmsg等があります。これらのコマンドはほとんどがPythonのスクリプトになっていますので、下の書式で起動できます。
 > python %ROS_HOME%bin\rosnode
 > python %ROS_HOME%bin\rostopic
 > python %ROS_HOME%bin\rosmsg
そのため、下のような内容のバッチファイルを作っておけば、コピーするだけで各コマンドの呼び出しが可能です。
python %ROS_HOME%bin\%0 %*

talker.pyとlistener.pyの作成と動作実行

最後に、ROSチュートリアルのtalker.pyとlistener.pyを作成して動作確認を行います。この時注意すべきことは、rospy.loginfoを使うとrosoutが起動していないためにメッセージが表示されません。
必要に応じてprint文などに置き換えてください。
  • talkey.py
import rospy
from std_msgs.msg import String

def talker():
    pub=rospy.Publisher('chatter', String, queue_size=10)
    rospy.init_node('talker', anonymous=True)
    rate=rospy.Rate(10)
    while not rospy.is_shutdown():
        hello_str="hello world %s" % rospy.get_time()
        #rospy.loginfo(hello_str)
        print(hello_str)
        pub.publish(hello_str)
        rate.sleep()

if __name__=='__main__':
    try:
        talker()
    except rospy.ROSInterruptException:
        pass
  • listener.py
import rospy
from std_msgs.msg import String

def callback(data):
    #rospy.loginfo(rospy.get_caller_id()+"I heard %s",data.data)
    print(rospy.get_caller_id()+"I heard %s" % data.data)

def listener():
    rospy.init_node('listener', anonymous=True)
    rospy.Subscriber("chatter", String, callback)
    rospy.spin()

if __name__ == '__main__':
    listener()
最後に起動して動作確認を行います。
 > start python %ROS_HOME%\bin\rosmaster --core -p 11311 -w 3
 > start python talker.py
 > python listener.py
これで、それぞれのウィンドウにメッセージが表示されればOKです。
もう少しデフォルトのROSに使づけたかったので、roscoreを動作させるようにしています。その2に続きます。