ROS講座68 xacroを使う1

# 環境
この記事は以下の環境で動いています。

| 項目 | 値 |
|:-:|:-:|
| CPU | Core i5-8250U |
| Ubuntu | 20.04 |
| ROS | Noetic |

インストールについては[ROS講座02 インストール](https://qiita.com/srs/items/e0e0a9dc3f94c2d3348e)を参照してください。
またこの記事のプログラムはgithubにアップロードされています。[ROS講座11 gitリポジトリ](https://qiita.com/srs/items/25a56a6abda41dcf396e)を参照してください。


# 概要
URDFにはプログラマブルな要素が一切ないので繰り返しのパターンなどもすべて書く必要があります。例えばタイヤが4つあるロボットでも4つのタイヤを別々に記述する必要があります。そこでxacro(Xml mACRO)という記法を使うことでこれを解決します。

#例1(property)
まずXacroの書式と一番基本的な機能であるpropertyを説明します。そしてXacroの使い方を説明します。

## ソースコード

```xml:vis_lecture/xacro/basic1.xacro
<robot name="test_robot" xmlns:xacro="http://ros.org/wiki/xacro">
  <xacro:property name="side" value="0.5" />

  <link name="base_link">
    <visual>
      <origin rpy="0 0 0" xyz="0 0 0"/>
      <geometry>
        <box size="${side} ${side} ${side}" />
      </geometry>
      <material name="red">
        <color rgba="1.0 0.0 0.0 2.0"/>
      </material>
    </visual>
  </link>
</robot>
```
ポイントを説明していきます。

* 1行目の`<robot>`タグの中の属性として`xmlns:xacro="http://ros.org/wiki/xacro"`を書きます。これを書かないとxacroとして認識されません。
* 2行目の`<xacro:property name="side" value="0.5" />`ではいわば定数の設定をしています。nameに変数名、valueに値を入れます。この値は数字、文字列、true/falseが使えます。
* 14行目の`<box size="${side} ${side} ${side}" />`では上で設定した「定数」を使用しています。この部分は後々`<box size="0.5  0.5 0.5" />`と解釈されます。

## 実行
上記のxacroファイルを指定して実行します。

```
roscd vis_lecture/xacro/
roslaunch urdf_tutorial display.launch model:=basic1.xacro
```

以下のようにRviz上に一辺0.5mの立方体が出現します。
（Fixed Frameをbase_linkに変更、RobotModelの表示の操作が必要です）
![vis_xacro1.png](https://qiita-image-store.s3.amazonaws.com/0/254442/a82f17b5-b9e2-17ef-b82f-1cac073acb6e.png)

# xacroファイルの変換と確認
デバッグ用にxacroファイルの変換とそれを確認する手段を説明します。

## xacroファイルのurdfへの展開を行う
以下のコマンドでxacroファイルを展開することができます。

```shell
roscd vis_lecture/xacro/
rosrun xacro xacro basic1.xacro --inorder >basic1.urdf
```

展開した中身を見てみましょう。

```xml:basic1.urdf(basic1.xacroを展開したもの)
<?xml version="1.0" ?>
<!-- =================================================================================== -->
<!-- |    This document was autogenerated by xacro from basic1.xacro                   | -->
<!-- |    EDITING THIS FILE BY HAND IS NOT RECOMMENDED                                 | -->
<!-- =================================================================================== -->
<robot name="test_robot" xmlns:xacro="http://ros.org/wiki/xacro">
  <link name="base_link">
    <visual>
      <origin rpy="0 0 0" xyz="0 0 0"/>
      <geometry>
        <box size="0.5 0.5 0.5"/>
      </geometry>
      <material name="red">
        <color rgba="1.0 0.0 0.0 2.0"/>
      </material>
    </visual>
  </link>
</robot>

```

確かに11行目で`<box size="0.5 0.5 0.5"/>`と正しく展開できています。

## エラーチェック
xacroが正しく展開できても、展開したurdfの書式が正しいかはわかりません。またこの辺りでエラーがあってもroslaunchで実行すると何が悪いのかわかりにくいです。以下のように`check_urdf`を使ってあらかじめ構文を確認するのをお勧めします。

```shell:xacroのエラーのチェック
roscd vis_lecture/xacro/
rosrun xacro xacro basic1.xacro --inorder >basic1.urdf
check_urdf basic1.urdf 
```

エラーがなかった場合は以下のような表示になります。

```shell:check_urdfのエラーがなかった時の結果
robot name is: test_robot
---------- Successfully Parsed XML ---------------
root Link: base_link has 0 child(ren)
```

# 例2（数式）

## ソースコード
```xml:vis_lecture/xacro/basic2.xacro
<robot name="test_robot" xmlns:xacro="http://ros.org/wiki/xacro">
  <xacro:property name="side" value="0.5" />
  <material name="red">
    <color rgba="1.0 0.0 0.0 2.0"/>
  </material>

  <link name="base_link"/>

  <joint name="body0_joint" type="fixed">
    <origin rpy="0 0 0" xyz="${0.5*cos(radians(0))} ${0.5*sin(radians(0))} 0"/>
    <parent link="base_link"/>
    <child  link="body0_link"/>
  </joint>
  <link name="body0_link">
    <visual>
      <geometry>
        <box size="0.1 0.1 0.1" />
      </geometry>
      <material name="red"/>
    </visual>
  </link>

  <joint name="body1_joint" type="fixed">
    <origin rpy="0 0 0" xyz="${0.5*cos(radians(30))} ${0.5*sin(radians(30))} 0"/>
    <parent link="base_link"/>
    <child  link="body1_link"/>
  </joint>
  <link name="body1_link">
    <visual>
      <geometry>
        <box size="0.1 0.1 0.1" />
      </geometry>
      <material name="red"/>
    </visual>
  </link>

  <joint name="body2_joint" type="fixed">
    <origin rpy="0 0 0" xyz="${0.5*cos(radians(60))} ${0.5*sin(radians(60))} 0"/>
    <parent link="base_link"/>
    <child  link="body2_link"/>
  </joint>
  <link name="body2_link">
    <visual>
      <geometry>
        <box size="0.1 0.1 0.1" />
      </geometry>
      <material name="red"/>
    </visual>
  </link>
</robot>
```

`<origin rpy="0 0 0" xyz="${0.5*cos(radians(0))} ${0.5*sin(radians(0))} 0"/>`のように数式を`${ }`で囲った中に書きます。この部分はpythonのeval()が実行されるようで、pythonデフォルトの関数と、mathライブラリの関数が使えます。

## 実行
```shell
roscd vis_lecture/xacro/
roslaunch urdf_tutorial display.launch model:=basic2.xacro 
```

以下のように円形に箱が並びます。
![vis_xacro2.png](https://qiita-image-store.s3.amazonaws.com/0/254442/d72c52e6-45ea-89f7-cda3-939f38ecccdf.png)

# 例3（条件式）

## ソースコード

```xml:vis_lecture/xacro/basic3.xacro
<robot name="test_robot" xmlns:xacro="http://ros.org/wiki/xacro">
  <xacro:property name="color" value="blue" />

  <material name="red">
    <color rgba="1.0 0.0 0.0 2.0"/>
  </material>
  <material name="blue">
    <color rgba="0.0 0.0 1.0 2.0"/>
  </material>

  <link name="base_link">
    <visual>
      <geometry>
        <box size="0.1 0.1 0.1" />
      </geometry>
      <xacro:if value="${color=='red'}">
        <material name="red"/>
      </xacro:if>
      <xacro:if value="${color=='blue'}">
        <material name="blue"/>
      </xacro:if>
    </visual>
  </link>
</robot>

```

`<xacro:if value="${color=='red'}">`から`</xacro:if>`の間がvalue属性の中の条件式が真の時のみ展開されます。またvalue値を指定するのにクォーテーションが必要で、また条件式で文字列を作るためにもクォーテーションを使います。両方同じクォーテーションを使うと誤動作するので、片方をダブルクォーテーションにして、もう片方をシングルクォーテーションにします。

## 実行

```shell
roscd vis_lecture/xacro/
roslaunch urdf_tutorial display.launch model:=basic3.xacro 
```

![vis_xacro3.png](https://qiita-image-store.s3.amazonaws.com/0/254442/7db4f3fb-05da-1003-8168-75c75fdfcb4e.png)

# 参考
[roswiki: xacro](ros.org/wiki/xacro)

# 目次ページへのリンク
[ROS講座の目次へのリンク](https://qiita.com/srs/items/5f44440afea0eb616b4a)