Yura YuLife

ITエンジニアの覚え書き。

ROS Pythonにおけるuint8[]の扱い方

ROSでuint8[]型を利用しているトピックをPythonで使う場合にハマった点です。

環境

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