Main Content

基本的な ROS 2 メッセージの操作

この例では、ロボティクス アプリケーションで一般に使用される ROS 2 メッセージの作成、検査、取り込みを MATLAB で行うためのさまざまな方法を調べます。

ROS "メッセージ" は、ROS 2 でデータを交換するための主要なコンテナーです。パブリッシャーとサブスクライバーは、指定された "トピック" のメッセージを使用してノード間でデータを伝達することでデータを交換します。メッセージ送受信の詳細については、ROS 2 のパブリッシャーとサブスクライバーとのデータ交換を参照してください。

それぞれのメッセージに、そのデータ構造を識別するための "メッセージ タイプ" があります。たとえば、レーザー スキャナーからのセンサー データは、一般に sensor_msgs/LaserScan タイプのメッセージで送信されます。各メッセージ タイプは、メッセージに含まれているデータ要素を識別します。それぞれのメッセージ タイプの名前は、パッケージ名の後にスラッシュ (/) とタイプ名を組み合わせた名前になります。

MATLAB® では、ロボティクス アプリケーションで一般に使用されるさまざまな ROS 2 メッセージ タイプをサポートしています。この例では、ROS 2 メッセージの作成、検査、取り込みを MATLAB で行うためのいくつかの方法を調べます。

前提条件:ROS 2 入門ROS 2 ネットワークへの接続

メッセージ タイプの特定

exampleHelperROS2CreateSampleNetwork を使用して、ROS 2 ネットワークに 3 つのノードを取り込み、特定のトピックに関するサンプルのパブリッシャーとサブスクライバーを設定します。

exampleHelperROS2CreateSampleNetwork

ros2 topic list -t を使用して、使用可能なトピックとそれらに関連付けられているメッセージ タイプを調べます。

ros2 topic list -t
            Topic                       MessageType           
    _____________________    _________________________________

    {'/parameter_events'}    {'rcl_interfaces/ParameterEvent'}
    {'/pose'            }    {'geometry_msgs/Twist'          }
    {'/rosout'          }    {'rcl_interfaces/Log'           }
    {'/scan'            }    {'sensor_msgs/LaserScan'        }

トピックのメッセージ タイプの詳細を調べるには、ros2message を使用して同じタイプの空のメッセージを作成します。ros2message では、メッセージ タイプのタブ補完がサポートされています。メッセージ タイプの完全な名前をすばやく入力するには、目的の名前の最初の数文字を入力して "Tab" キーを押します。

scanData = ros2message("sensor_msgs/LaserScan")
scanData = struct with fields:
        MessageType: 'sensor_msgs/LaserScan'
             header: [1×1 struct]
          angle_min: 0
          angle_max: 0
    angle_increment: 0
     time_increment: 0
          scan_time: 0
          range_min: 0
          range_max: 0
             ranges: 0
        intensities: 0

作成されたメッセージ scanData には、レーザー スキャナーから一般に受信するデータに関連する多数のフィールドが含まれています。たとえば、range_min プロパティには最小検出距離、range_max プロパティには最大検出距離が格納されます。

ここで、作成されたメッセージは削除できます。

clear scanData

トピックとサービスについての使用可能なすべてのメッセージ タイプの完全なリストを確認するには、ros2 msg list を使用します。

メッセージ構造体の確認とメッセージ データの取得

ROS 2 メッセージは構造体として表され、フィールドにメッセージ データが格納されます。MATLAB には、メッセージの内容を特定して確認できる便利な方法が用意されています。

ros2 msg show を使用して、メッセージ タイプの定義を確認します。

ros2 msg show geometry_msgs/Twist
# This expresses velocity in free space broken into its linear and angular parts.

Vector3  linear
Vector3  angular

/pose トピックをサブスクライブすると、送信されるメッセージを受信して調べることができます。

controlNode = ros2node("/base_station");
poseSub = ros2subscriber(controlNode,"/pose","geometry_msgs/Twist")
poseSub = 
  ros2subscriber with properties:

        TopicName: '/pose'
    LatestMessage: []
      MessageType: 'geometry_msgs/Twist'
    NewMessageFcn: []
          History: 'keeplast'
            Depth: 10
      Reliability: 'reliable'
       Durability: 'volatile'

receive を使用して、サブスクライバーからデータを取得します。新しいメッセージを受信すると、そのメッセージが関数から返されて posedata 変数に格納されます。メッセージの受信のタイムアウトを 10 秒と指定します。

poseData = receive(poseSub,10)
poseData = struct with fields:
    MessageType: 'geometry_msgs/Twist'
         linear: [1×1 struct]
        angular: [1×1 struct]

メッセージのタイプは geometry_msgs/Twist です。メッセージには、このほかに linearangular の 2 つのフィールドがあります。それらのメッセージ フィールドに直接アクセスして、それらの値を確認できます。

poseData.linear
ans = struct with fields:
    MessageType: 'geometry_msgs/Vector3'
              x: 0.0206
              y: -0.0468
              z: -0.0223

poseData.angular
ans = struct with fields:
    MessageType: 'geometry_msgs/Vector3'
              x: -0.0454
              y: -0.0403
              z: 0.0323

それらの各メッセージ フィールドの値自体が実際にはメッセージであることがわかります。geometry_msgs/Twist は、geometry_msgs/Vector3 の 2 つのメッセージで構成される複合メッセージです。

それらの入れ子になったメッセージのデータ アクセスも、他のメッセージのデータにアクセスする場合とまったく同じです。次のコマンドを使用して linear メッセージの x 成分にアクセスします。

xPose = poseData.linear.x
xPose = 0.0206

メッセージ データの設定

メッセージ プロパティの値を設定することもできます。タイプが geometry_msgs/Twist のメッセージを作成します。

twist = ros2message("geometry_msgs/Twist")
twist = struct with fields:
    MessageType: 'geometry_msgs/Twist'
         linear: [1×1 struct]
        angular: [1×1 struct]

このメッセージの数値プロパティは、既定では 0 に初期化されます。このメッセージの任意のプロパティを変更できます。linear.y フィールドを 5 に設定します。

twist.linear.y = 5;

メッセージ データを表示して、変更が反映されたことを確認できます。

twist.linear
ans = struct with fields:
    MessageType: 'geometry_msgs/Vector3'
              x: 0
              y: 5
              z: 0

メッセージにデータが取り込まれたら、それをパブリッシャーおよびサブスクライバーで使用できます。

メッセージのコピー

ROS 2 メッセージは構造体です。それらをそのままコピーして新しいメッセージを作成できます。コピーと元のメッセージは、それぞれ独自のデータをもちます。

温度データを伝達する新しい空のメッセージを作成し、変更用にそのコピーを作成します。

tempMsgBlank = ros2message("sensor_msgs/Temperature");
tempMsgCopy = tempMsgBlank
tempMsgCopy = struct with fields:
    MessageType: 'sensor_msgs/Temperature'
         header: [1×1 struct]
    temperature: 0
       variance: 0

tempMsg の temperature プロパティを変更し、tempMsgBlank の内容は変わらないことを確認します。

tempMsgCopy.temperature = 100
tempMsgCopy = struct with fields:
    MessageType: 'sensor_msgs/Temperature'
         header: [1×1 struct]
    temperature: 100
       variance: 0

tempMsgBlank
tempMsgBlank = struct with fields:
    MessageType: 'sensor_msgs/Temperature'
         header: [1×1 struct]
    temperature: 0
       variance: 0

空白のメッセージ構造体を用意し、データがあるときにだけ特定のフィールドを設定してメッセージを送信すると便利な場合があります。

thermometerNode = ros2node("/thermometer");
tempPub = ros2publisher(thermometerNode,"/temperature","sensor_msgs/Temperature");
tempMsgs(10) = tempMsgBlank;    % Pre-allocate message structure array
for iMeasure = 1:10
    % Copy blank message fields
    tempMsgs(iMeasure) = tempMsgBlank;
    
    % Record sample temperature
    tempMsgs(iMeasure).temperature = 20+randn*3;
    
    % Only calculate the variation once sufficient data observed
    if iMeasure >= 5
        tempMsgs(iMeasure).variance = var([tempMsgs(1:iMeasure).temperature]);
    end
    
    % Pass the data to subscribers
    send(tempPub,tempMsgs(iMeasure))
end
errorbar([tempMsgs.temperature],[tempMsgs.variance])

メッセージの保存と読み込み

後で使用するためにメッセージを保存して内容を格納できます。

サブスクライバーから新しいメッセージを取得します。

poseData = receive(poseSub,10)
poseData = struct with fields:
    MessageType: 'geometry_msgs/Twist'
         linear: [1×1 struct]
        angular: [1×1 struct]

関数saveを使用して、姿勢データを MAT ファイルに保存します。

save("poseFile.mat","poseData")

ファイルをワークスペースに再度読み込む前に、poseData 変数をクリアします。

clear poseData

これで、関数loadを呼び出してメッセージ データを読み込むことができます。これにより、上記の poseDatamessageData 構造体に読み込まれます。poseData は struct のデータ フィールドです。

messageData = load("poseFile.mat")
messageData = struct with fields:
    poseData: [1×1 struct]

messageData.poseData を調べてメッセージの内容を確認します。

messageData.poseData
ans = struct with fields:
    MessageType: 'geometry_msgs/Twist'
         linear: [1×1 struct]
        angular: [1×1 struct]

ここで、MAT ファイルは削除できます。

delete("poseFile.mat")

ROS 2 ネットワークからの切断

サンプル ノード、パブリッシャー、およびサブスクライバーを ROS 2 ネットワークから削除します。

exampleHelperROS2ShutDownSampleNetwork

次のステップ