ROSの勉強　第48弾：Xacroチュートリアルのまとめ

# #プログラミング ROS< Xacroチュートリアルのまとめ >

## はじめに
ROS(Robot Operating System)をさらに扱えるようになることが目的である．その第48弾として，「Xacroチュートリアルのまとめ」を扱う．

## 環境
##### Docker環境（VScode + Windows10）
<details><summary>Dockerfile</summary>

```dockerfile:Dockerfile
FROM osrf/ros:noetic-desktop-full

WORKDIR /root/

ENV DISPLAY host.docker.internal:0.0

RUN apt-get update -y && apt-get upgrade -y
RUN apt-get install x11-apps -y
RUN echo "source /opt/ros/noetic/setup.sh" >> .bashrc
RUN mkdir -p catkin_ws/src
RUN cd catkin_ws/src && . /opt/ros/noetic/setup.sh && catkin_init_workspace
RUN cd && cd catkin_ws && . /opt/ros/noetic/setup.sh && catkin_make
RUN echo "source ./catkin_ws/devel/setup.bash" >> .bashrc

RUN apt-get update -y && apt-get upgrade -y && apt-get install git -y
```

</details>


<details><summary>devcontainer.json</summary>


```json:devcontainer.json
// For format details, see https://aka.ms/devcontainer.json. For config options, see the README at:
// https://github.com/microsoft/vscode-dev-containers/tree/v0.224.3/containers/docker-existing-dockerfile
{
	"name": "Existing Dockerfile",

	// Sets the run context to one level up instead of the .devcontainer folder.
	"context": "..",

	// Update the 'dockerFile' property if you aren't using the standard 'Dockerfile' filename.
	"dockerFile": "../Dockerfile",

	// Set *default* container specific settings.json values on container create.
	"settings": {},
	
	// Add the IDs of extensions you want installed when the container is created.
	"extensions": [
		"ms-python.python",
		"ms-python.vscode-pylance",
		"ms-iot.vscode-ros"
	],

	"workspaceFolder": "/root/",

	"mounts": [
		"source=${localWorkspaceFolder}/share,target=/root/share,type=bind",
	],
	// // Use 'forwardPorts' to make a list of ports inside the container available locally.
	// // "appPort": ["11411:11411"],

	// // Uncomment the next line to run commands after the container is created - for example installing curl.
	// // "postCreateCommand": "apt-get update && apt-get install -y curl",

	// // Uncomment when using a ptrace-based debugger like C++, Go, and Rust
	"runArgs": ["--gpus=all"],

	// Uncomment to use the Docker CLI from inside the container. See https://aka.ms/vscode-remote/samples/docker-from-docker.
	// "mounts": ["source=../src/,target=/root/src,type=bind"],
	// "mounts": [ "source=../src,target=/root/src,type=bind" ],

	// Uncomment to connect as a non-root user if you've added one. See https://aka.ms/vscode-remote/containers/non-root.
	// "remoteUser": "vscode"
}

```

</details>

**参考**

https://qiita.com/Yuya-Shimizu/items/22c6a2a473139d15857f


##### コンピュータ
|||
|:-:|:--|
|デバイス|MSI|
|プロセッサ|Intel(R) Core(TM) i5-7300HQ CPU @ 2.50GHz 2.50GHz|
|実装RAM|16.0 GB (15.9 GB 使用可能)|
|OS|Windows (Windows 10 Home, バージョン：22H2)|

##### ROS
|||
|:-:|:--|
|Distribution|noetic|


## Xacroの基本

### Xacroファイルのトップに必要

```xml
<?xml version="1.0"?>
<robot xmlns:xacro="http://www.ros.org/wiki/xacro" name="firefighter">
```

### urdfからxacro（不変から可変）

<details><summary>不変＜urdf＞</summary> 

```xml
<link name="base_link">
    <visual>
      <geometry>
        <cylinder radius="0.2" length="0.6"/>
      </geometry>
      <material name="blue"/>
    </visual>
    <collision>
      <geometry>
        <cylinder radius="0.2" length="0.6"/>
      </geometry>
    </collision>
  </link>
```

</details>

<details><summary>可変＜xacro＞</summary>

```xml
<xacro:property name="width" value="0.2" />
<xacro:property name="bodylen" value="0.6" />
<link name="base_link">
    <visual>
        <geometry>
            <cylinder radius="${width}" length="${bodylen}"/>
        </geometry>
        <material name="blue"/>
    </visual>
    <collision>
        <geometry>
            <cylinder radius="${width}" length="${bodylen}"/>
        </geometry>
    </collision>
</link>
```
</details>

``<xacro:property>``タグにより変数名とその値を宣言できる

### ${}の使い方

```xml
<xacro:property name="robotname" value="marvin" />
<link name="${robotname}s_leg" />
```

${}のところに値が代入される。文字の結合ができる。

変数代入結果

```xml
<link name="marvins_leg" />
```

### 数学的処理

```xml
<cylinder radius="${wheeldiam/2}" length="0.1"/>
<origin xyz="${reflect*(width+.02)} 0 0.25" />
```

計算結果はすべてfloatとなる。そのため、

```xml
<link name="${5/6}"/>
```

は

```xml
<link name="0.833333333333"/>
```

となる。

### シンプルなマクロ

```xml
<xacro:macro name="default_origin">
    <origin xyz="0 0 0" rpy="0 0 0"/>
</xacro:macro>
<xacro:default_origin />
```

マクロは関数的なものである。
``<xacro:default_origin />``で関数を実行する。

### パラメータ（引数）付きマクロ

```xml
<xacro:macro name="default_inertial" params="mass">
    <inertial>
        <mass value="${mass}" />
        <inertia ixx="1.0" ixy="0.0" ixz="0.0"
							             iyy="1.0" iyz="0.0"
												             izz="1.0" />
    </inertial>
</xacro:macro>
```

関数を使うときには、引数を指定できる。
``
<xacro:default_inertial mass="10"/>
``

### 挿入ブロック付きマクロ

```xml
<xacro:macro name="blue_shape" params="name *shape">
    <link name="${name}">
        <visual>
            <geometry>
                <xacro:insert_block name="shape" />
            </geometry>
            <material name="blue"/>
        </visual>
        <collision>
            <geometry>
                <xacro:insert_block name="shape" />
            </geometry>
        </collision>
    </link>
</xacro:macro>

<xacro:blue_shape name="base_link">
    <cylinder radius=".42" length=".01" />
</xacro:blue_shape>
```

``<xacro:insert_block name="shape" />``
により、関数を使うときにブロックごと挿入することができる。

### 作成例

同じ構造を持つ足を２本生成
<details><summary>leg_macro.xacro＜xacro＞</summary>

```xml:leg_macro.xacro
<?xml version="1.0"?>
<robot xmlns:xacro="http://ros.org/wiki/xacro">

    <xacro:macro name="leg" params="prefix reflect width">
        <link name="${prefix}_leg">
            <visual>
                <geometry>
                        <box size="${leglen} 0.1 0.2"/>
                </geometry>
                <origin xyz="0 0 -${leglen/2}" rpy="0 ${pi/2} 0"/>
                <material name="white"/>
            </visual>
            <collision>
                <geometry>
                        <box size="${leglen} 0.1 0.2"/>
                </geometry>
                <origin xyz="0 0 -${leglen/2}" rpy="0 ${pi/2} 0"/>
            </collision>
            <xacro:default_inertial mass="10"/>
        </link>

        <joint name="base_to_${prefix}_leg" type="fixed">
            <parent link="base_link"/>
            <child link="${prefix}_leg"/>
            <origin xyz="0 ${reflect*(width+.02)} 0.25" />
        </joint>
        <!-- A bunch of stuff cut -->
    </xacro:macro>
</robot>
```
</details>
<details><summary>material_colors.xacro＜xacro＞</summary>

```xml:material_colors.xacro
<?xml version="1.0"?>
<robot xmlns:xacro="http://ros.org/wiki/xacro">

<!-- Define Material Colors -->
<material name="white">
    <color rgba="1.0 1.0 1.0 1.0"/>
</material>

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

<material name="green">
    <color rgba="0.0 1.0 0.0 1.0"/>
</material>

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

<material name="yellow">
    <color rgba="1.0 1.0 0.0 1.0"/>
</material>

<material name="cyan">
    <color rgba="0.0 1.0 1.0 1.0"/>
</material>

<material name="purple">
    <color rgba="1.0 0.0 1.0 1.0"/>
</material>

<material name="black">
    <color rgba="0.0 0.0 0.0 1.0"/>
</material>

</robot>
```

</details>
<details><summary>test.xacro＜xacro＞</summary>

```xml:test.xacro
<?xml version="1.0"?>
<robot xmlns:xacro="http://www.ros.org/wiki/xacro" name="My_Robot_Name">
	<xacro:include filename="$(find urdf_test)/urdf/xacro_test/material_colors.xacro" />
	<xacro:include filename="$(find urdf_test)/urdf/xacro_test/leg_macro.xacro" />

	<xacro:property name="leglen" value="0.6" />
	<xacro:property name="width" value="0.2" />

	<xacro:macro name="default_inertial" params="mass">
		<inertial>
			<mass value="${mass}" />
			<inertia ixx="1.0" 	ixy="0.0"	ixz="0.0"
													iyy="1.0" iyz="0.0"
																		izz="1.0" />
		</inertial>
	</xacro:macro>

	<xacro:leg prefix="right" reflect="1" width="${width}"/>
	<xacro:leg prefix="left" reflect="-1" width="${width}"/>

</robot>
```

</details>

---

### マクロテンプレート
これをテンプレートとして抑えておけば，様々なマクロを容易に作成できる．

```xml
<?xml version="1.0"?>
<robot xmlns:xacro="http://ros.org/wiki/xacro">

<xacro:macro name="macro_name" params="name mass length">

</xacro:macro>

</robot>
```

### xacro to urdf
ターミナル上で以下のコマンドにより，XacroをURDFに変換することができる．
なお，URDFの名前は任意である．

```bash:ターミナル上で実行する
xacro test.xacro > test.urdf
```

### xacroをそのまま（ロード時に変換）
URDFに変換せずとも，そのままXacroファイルをロードすることができる．
launchファイルのrobot_descriptionのところを以下のようにする．

```xml
<param name="robot_description"
  command="xacro --inorder '$(find pr2_description)/robots/pr2.urdf.xacro'" />
```

注意：直接Xacroから構築するためロードには少し時間がかかる


## 感想
前回のURDFをXacroファイルで体系的にまとめていく前に，Xacroのチュートリアルについてまとめてみた．マクロのやマクロのインポートなどを駆使すればいい感じにまとめていけそうな感じがする．
次回こそ，前回のURDFをきれいにしていくこととする．

## 参考文献

https://wiki.ros.org/urdf/Tutorials/Using%20Xacro%20to%20Clean%20Up%20a%20URDF%20File