ROS開発にPyCharmやCLionを使う際のTips
この記事では ROS の開発に Jetbrains 製の IDE である PyCharm や CLion を使う際に、便利に開発を進めるための設定を紹介しています。
環境
- Ubuntu 16.04 (14.04)
- ROS Kinetic (Indigo)
- PyCharm 2016.X
- CLion 2016.X
環境変数を設定
Ubuntu にインストールした PyCharm や CLion をランチャーから起動すると、ROS の環境変数が読み込まれておらず、ROSの関数やメッセージを import / include すると not found とワーニングが表示されます。
そこで、ROSの環境変数を読み込んだターミナルから IDE を起動してあげることで、メッセージや関数が正しく補完されるようになります。
$ source /opt/ros/kinetic/setup.bash # ROS Kinetic の場合 $ source /opt/ros/indigo/setup.bash # ROS Indigo の場合 $ source ~/catkin_ws/devel/setup.bash $ clion & # CLion をバックグラウンドで起動 $ charm & # PyCharm をバックグラウンドで起動
追記(2016/10/27)
以下のように Unity の launcher ファイルを書き換えることで、シェルから IDE を立ち上げる必要がなくなります。
PyCharmの場合 ~/.local/share/applications/jetbrains-pycharm.desktop
CLionの場合 ~/.local/share/applications/jetbrains-clion.desktop
[Desktop Entry] Version=1.0 Type=Application ... # 以下の行を削除 Exec=bash -c "/path/to/your/clion/bin/pycharm.sh %f" # PyCharm Exec=bash -c "/path/to/your/clion/bin/clion.sh %f" # CLion # 以下の行を追記する(PyCharm, ROS Kinetic の場合) Exec=bash -c "source /opt/ros/kinetic/setup.bash; source /path/to/your/catkin_ws/devel/setup.bash; /path/to/your/pycharm/bin/pycharm.sh" %f # 以下の行を追記する(CLion, ROS Kinetic の場合) Exec=bash -c "source /opt/ros/kinetic/setup.bash; source /path/to/your/catkin_ws/devel/setup.bash; /path/to/your/clion/bin/clion.sh" %f ...
型ヒントを利用 (PyCharm)
Python の docstring に変数や戻り値の型を記述すると、PyCharm がメンバ変数の補完や型の誤りの指摘をしてくれます。
例えば、PoseStamped 型のトピックのコールバック関数を例に取るとこんな感じです。
import math import rospy from geometry_msgs.msg import PoseStamped def callback_pose(pose): u""" PoseStamped のトピックのコールバック :param geometry_msgs.msg.PoseStamped pose: 変数 pose に関する説明 :rtype: float # 関数の戻り値の型 :return: pose の原点からの距離 # 関数の戻り値の説明 """ # pose. と打つと pose を補完、 pose.pose と打つと position や orientation を補完してくれる position = pose.pose.position distance = math.sqrt(position.x ** 2 + position.y ** 2 + position.z ** 2) return distance rospy.Subscriber("/some/topic", PoseStamped, callback_pose)
ROS の Pose 型と PoseStamped 型などは間違いやすいうえ、Python だと実行するまで気づけなかったりするので、PyCharm の type hinting を活用するとミスが減って効率アップできます。
参考URL
FTDI FT2232C用のudevルール
FTDIのFT2232C (Dual RS-232)というUSBシリアルを接続した際に、他のデバイスと識別できるよう、/dev/
以下にシンボリックリンクを作成するudevのルールです。
通常のUSBデバイスならば、Vendor IdとProduct Idを指定すれば良いのですが、FT2232Cは2つのシリアルポートが存在するため、少し工夫が必要です。
環境
- Ubuntu 14.04
USBデバイスとして認識していることを確認
lsusb
コマンドを実行して、 ベンダーIDとプロダクトIDが0403
, 6010
なるデバイスが存在することを確認します。
$ lsusb | grep "0403:6010" Bus XXX Device XXX: ID 0403:6010 Future Technology Devices International, Ltd FT2232C Dual USB-UART/FIFO IC
udevルールの作成
99-ft2232c.rules
というファイルを以下の内容で作成します。
# udev rule for FT2232C (Dual USB-UART/FIFO IC) ACTION=="add", SUBSYSTEMS=="usb", ATTRS{interface}=="Dual RS232", SYMLINK+="ft2232c-%s{bInterfaceNumber}"
作成したファイルを /etc/udev/rules.d/
以下にコピーします。
$ sudo cp 99-ft2232c.rules /etc/udev/rules.d/
シンボリックリンクが貼られたことを確認
USBケーブルを抜き差しすると、 /dev/ft2232c-00
, /dev/ft2232c-01
として、2つのシリアルポートが認識されていることが確認できます。
$ ls -al /dev/ | grep USB lrwxrwxrwx 1 root root 7 7月 25 18:48 ft2232c-00 -> ttyUSB0 lrwxrwxrwx 1 root root 7 7月 25 18:48 ft2232c-01 -> ttyUSB1 crw-rw-rw- 1 root dialout 188, 0 7月 25 14:07 ttyUSB0 crw-rw---- 1 root dialout 188, 1 7月 25 18:53 ttyUSB1
参考URL
ROS Pythonでオイラー角とクォータニオンの相互変換
ROSでオイラー角とクォータニオンを変換するには、tfパッケージの関数を利用すれば良いのですが、 単体の関数として使うには少々使いづらいので、簡単なラッパー関数を作りました。
オイラー角からクォータニオンへの変換
import tf from geometry_msgs.msg import Quaternion def euler_to_quaternion(euler): """Convert Euler Angles to Quaternion euler: geometry_msgs/Vector3 quaternion: geometry_msgs/Quaternion """ q = tf.transformations.quaternion_from_euler(euler.x, euler.y, euler.z) return Quaternion(x=q[0], y=q[1], z=q[2], w=q[3])
実行例
>>> import math >>> euler_to_quaternion(Vector3(0.0, 0.0, 0.0)) x: 0.0 y: 0.0 z: 0.0 w: 1.0 >>> euler_to_quarternion(Vector3(0.0, 0.0, math.pi / 2.0)) x: 0.0 y: 0.0 z: 0.707106781187 w: 0.707106781187
クォータニオンからオイラー角への変換
import tf from geometry_msgs.msg import Vector3 def quaternion_to_euler(quaternion): """Convert Quaternion to Euler Angles quarternion: geometry_msgs/Quaternion euler: geometry_msgs/Vector3 """ e = tf.transformations.euler_from_quaternion((quaternion.x, quaternion.y, quaternion.z, quaternion.w)) return Vector3(x=e[0], y=e[1], z=e[2])
実行例
>>> quaternion_to_euler(Quaternion(0.0, 0.0, 0.0, 1.0)) x: 0.0 y: -0.0 z: 0.0 >>> quaternion_to_euler(Quaternion(0.0, 0.0, 0.7071, 0.7071)) x: 0.0 y: -0.0 z: 1.57079632679
参考URL
ROS Pythonにおけるuint8[]の扱い方
ROSでuint8[]
型を利用しているトピックをPythonで使う場合にハマった点です。
環境
- Ubuntu 14.04
- ROS Indigo
rospyにおけるuint8[]
型の扱い
ROSのメッセージ型に関するリファレンスを参照すると、uint8[]
型について以下のような記述があります。
uint8 has special meaning in Python. uint8[] is treated as a Python bytes so that it is compatible with other byte-oriented APIs in Python.
rospy treats
uint8[]
data as a bytes, which is the Python representation for byte data. In Python 2, this is the same as str.
Pythonでは、ROSのuint8[]
型がbytes型(Python 2系ではstr型)として扱われるらしく、これは時に厄介な問題を引き起こします。
発生した問題
とあるセンサー群の測定値を測定するメッセージ型を以下のように定義しました。
foo_package/msg/FooSensor.msg
uint8[] value
そして、以下のようなシンプルなPublisherとSubscriberを作成しました。
publisher.py
import rospy from foo_package.msg import FooSensor def publish(): publisher = rospy.Publisher('/foo', FooSensor, queue_size=1) value = FooSensor(value=[100, 110, 120]) r = rospy.Rate(1.0) while not rospy.is_shutdown(): publisher.publish(value) r.sleep() publish()
subscriber.py
import rospy from foo_package.msg import FooSensor def callback(data): rospy.loginfo(data) rospy.loginfo(data.value) def subscribe(): rospy.Subscribe('/foo', FooSensor, callback) rospy.spin() subscribe()
publisher.py
, subscriber.py
を実行すると、以下のような2つのINFOレベルのログが出力されます。
- [INFO] [WallTime: 1461145922.975544] value: [100, 110, 120]
- [INFO] [WallTime: 1461145941.678116] dnx
data
自体を出力すると、valueにint型の数値が入っているのが確認できるのですが、data.value
を出力するとdnx
という文字列が出力されてしまい、配列の要素をint型として利用することが出来ません。
対処方法
対処方法はあまり根本的なものではないのですが、valueの各要素のASCIIコードが本来のintの値なので、ord
関数で変換してあげることでint型の配列を得ることが出来ます。
def callback(data): int_array = [ord(n) for n in data.value] rospy.logwarn(int_array)
再度実行すると[100, 110, 120]
という配列が出力されます。
ただし、この処理は直感的でなく、uint8[]
型以外に対してはエラーを返すため、あまりオススメできません。出来れば、メッセージ型の定義部分でuint16[]
等を利用することで回避するのが好ましいと思われます。
参考URL
BitBucketとWerckerでウェブサイトを自動デプロイ
タイトルの通り。BitBucketとWerckerとFTP(lftp)で静的なウェブサイトを自動デプロイする方法です。
ちなみにBitBucketとWerckerを使っているのは、プライベートリポジトリを無料で使えるから。
BitBucketの設定
- Gitのリポジトリを作って、ウェブサイトのファイルをコミットしておきます
Werckerの設定
Applicationの作成
- 画面上部のCreateからApplicationを追加します。
- Choose a repositoryでは、先ほど作成したBitBucketのリポジトリを選択します。
- Ownerの設定は自分のアカウントか、共有で管理するならばOrganizationを選択します。
- Configure accessは、recommendedの設定をそのまま利用すれば大丈夫です。
デプロイ設定
アプリケーションを作成したら、SettingsのTargetsから、デプロイターゲットの設定をします。
- Deploy target nameには適当な名前を設定します。
- Auto deployにチェックを入れておくと、ビルド成功時に自動でデプロイが行われます
- また、デプロイ対象となるブランチ名(通常はmaster)を入力します。
環境変数の設定
SettingsのEnvironmental Variablesに以下のKey, Valueのペアを登録しておきます。
FTP_SERVER_URL
: サーバのURL(ftp.example.comなど)FTP_USERNAME
: FTPのユーザ名(Protectedを推奨)FTP_PASSWORD
: FTPのパスワード(Protectedを推奨)
環境変数をProtectedにしておくと管理画面等で変数の内容が表示されないので、パスワード等の情報は必ずProtectedにしておくことを推奨します。
wercker.ymlの追加
リポジトリのルートにwercker.yml
として、以下のファイルを追加します。
# This references a standard debian container from the # Docker Hub https://registry.hub.docker.com/_/debian/ # Read more about containers on our dev center # http://devcenter.wercker.com/docs/containers/index.html box: debian # This is the build pipeline. Pipelines are the core of wercker # Read more about pipelines on our dev center # http://devcenter.wercker.com/docs/pipelines/index.html build: # Steps make up the actions in your pipeline # Read more about steps on our dev center: # http://devcenter.wercker.com/docs/steps/index.html steps: - script: name: echo code: | echo "Build finished!" deploy: steps: - install-packages: packages: lftp - script: name: upload files via FTP code: | lftp -u ${FTP_USERNAME},${FTP_PASSWORD} -e "set ssl:verify-certificate no;mirror -Rev -X wercker.yml アップロード元(リポジトリ)のディレクトリ/. アップロード先(サーバ)のディレクトリ/." ${FTP_SERVER_URL}
上記の設定ファイルによって、リモートリポジトリへのpush時にWerckerで以下の内容が実行されます。
- ビルドとデプロイを行うための、debianのboxを作成
- ビルド時に
echo "Build finished!"
を実行 - デプロイ時にlftpをインストール
- lftpコマンドでリポジトリ内のファイルをサーバへミラーリングアップロード(ただしwercker.ymlはアップロードしない)
デプロイの実行
上記の設定が済んだら変更内容をcommitし、リモートリポジトリのmasterブランチへpushを行います。
ビルドやデプロイに失敗するとWerckerからメール通知が来るので、エラーメッセージを読んで適宜修正を行います。
slackへの通知
wercker.yml
に以下の行を追加すると、デプロイ(もしくはビルド)時にslackへ通知を飛ばすことができます。
after-steps: - slack-notifier: url: $SLACK_WEBHOOK_URL username: Wercker
slack側で事前にIncoming WebhookのURLを取得し、Werckerの環境変数にSLACK_WEBHOOK_URL
として当該URLを登録しておくことでslackに通知が飛びます。