ROS練習用のロボットを作る

　ロボット用ミドルウェアであるところの[ROS](http://www.ros.org/)の勉強をしたいわけなんですが，ROS対応のロボットと言うと，[こんなの](http://nextage.kawada.jp/open/)とか，[こんなの](http://www.bostondynamics.com/robot_Atlas.html)とか，安いのでも[こんなの](http://www.nihonbinary.co.jp/Products/Robot/TurtleBot.html)くらいは必要で，とてもちょろっと試してみるくらいの費用じゃできないんですよね．
　それでも僕は，ROSが使いたいんだ！！
　と言うわけで，なるべく最小限の費用でROS練習用のロボットを作ることにしました．

# 作ったロボット
![ROS制御アーム](https://pbs.twimg.com/media/B7RztmbCMAEsBRr.jpg "ROS制御アーム")

　[こんなかんじ](https://twitter.com/k_yone/status/553130973525983233)に動きます．
　今回は[Intel Edison](http://www.intel.co.jp/content/www/jp/ja/do-it-yourself/edison.html)で動かしました．

# 必要なもの
## ハードウェア
- [GWSサーボ Micro 2BB/MG](http://akizukidenshi.com/catalog/g/gM-01725/) ×2
- [サーボブラケット](http://www.marutsu.co.jp/pc/i/18781/) ×2
- スマホ固定アーム
- USBカメラ
- 配線材料
- 5[V]くらい出るACアダプタ
- PWMが出せる制御ボード（今回はIntel Edison）
- 母艦PC（Ubuntuオススメ）

　スマホ固定アームにハンドドリルで穴をあけて，サーボブラケットを固定しました．同様に，USBカメラの背面にも穴をあけてブラケットに固定しています．ネジやナットは適当に身の回りにあったものを使用しました．

## ソフトウェア
- [ROS](http://www.ros.org/) ロボット陽ミドルウェア
- [Gazebo](http://gazebosim.org/) 物理シミュレータ
- [libmraa](http://iotdk.intel.com/docs/master/mraa/) Intel Edisonのインタフェース
- [ros_gpio](https://github.com/yoneken/ros_gpio) ROSの制御ボード用インタフェース

# 組立て
　フィーリングで．
　サーボモータと制御ボードの間の配線は，[このあたり](http://qiita.com/yoneken/items/8667be9d40d29a295085)を参照のこと．

# ソフトウェアの準備
　母艦PCとEdisonにROSをインストール．Edisonへのインストールは，[ここ](http://qiita.com/yoneken/items/eda0bedec847761088c1)を参照．母艦PCへは，[こちら](http://wiki.ros.org/indigo/Installation/Source)の **Desktop-Full Install** を行う．libmraaのインストールは[こちら](http://www.cannon-ball.info/pukiwiki/index.php?DIY%2FEdison%2FL%E3%83%81%E3%82%AB)，ros_gpioは，ROSのsrcディレクトリで，
> wstool set --git ros_gpio https://github.com/yoneken/ros_gpio.git
> wstool update ros_gpio

# ロボットの物理モデル作成
　ROSでは，ロボットの関節軸構成や物理モデルを記述するのに，Unified Robot Description Format (URDF)を使います．[英語の説明](http://wiki.ros.org/urdf/Tutorials/Building%20a%20Visual%20Robot%20Model%20with%20URDF%20from%20Scratch)を読み進めながら書きましょう．今回ターゲットとなるロボットの関節軸構造は，以下のようになっています．

![関節軸構造](https://pbs.twimg.com/media/B7UYWZMCYAA3sZl.png "関節軸構造")

## データ構造
### &lt;robot name=" *robot_name* "&gt;
　XML全体をくくり，一体のロボットを宣言するタグです． *robot_name* のところには，任意の名前を入れてください．

　ロボットのデータ構造は，リンクとジョイント（関節）の連なったチェーン構造で表現されます．

### &lt;link name=" *link_name* "&gt;
　 *link_name* のところには，ロボット内で一意の名前を入れてください．

### &lt;joint name=" *joint_name* " type=" *joint_type* "&gt;
　 *joint_name* のところには，ロボット内で一意の名前を入れてください． *joint_type* のところには，
- revolute : ヒンジ機構．上限・下限が必要．
- continuous : 無限回転機構
- prismatic : 直動機構．上限・下限が必要．
- fixed : 固定関節．
- floating : 自由関節．
- planar : 水平移動機構．
の各種タイプのうち，どれか一つを入れてください．

　このjoint要素の中で， **parent** ， **child** ， **origin** の要素を定義します．さらに必要に応じて， **axis** ， **limit** ， **dynamics** の要素も定義します．
#### &lt;parent link=" *link_name* "&gt;
　 *link_name* のところには，ジョイントの根元となるリンクの名前を入れてください．
#### &lt;child link=" *link_name* "&gt;
　 *link_name* のところには，ジョイントの先につながるリンクの名前を入れてください．
#### &lt;origin xyz=" *xyz_val* " rpy=" *rpy_val* "&gt;
　 *xyz_val* のところには，ジョイントの根元となるリンクの原点を基準とした，ジョイントのxyz距離[m]を入れてください．ロボットの座標系は，前方向がx軸，左手方向がy軸，垂直方向がz軸の右手系が標準です． *rpy_val* のところには，回転させる角度[rad]を入れてください．
>例．
>&lt;origin xyz="0 0 0.088" rpy="0 0.5236 0"&gt;

#### &lt;axis xyz=" *xyz_val* "&gt;
　revoluteやcontinuousといった回転関節の場合は，回転軸の方向をaxisタグで定義します．方向は，右ネジの方向です．
#### &lt;limit lower=" *lower_lim* " uppper=" *upper_lim* " effort=" *effort_lim* " velocity=" *vel_lim* "&gt;
　revoluteやprismatic，といった上限・下限がある関節の場合は，lower_limとupper_limの値を適切に設定してください．これらに加えて，continuous関節の場合は，セーフティとしてeffort_limとvelocity_limの値も設定してください．計算方法は[こちら](http://wiki.ros.org/pr2_controller_manager/safety_limits)．


　実際にチェーンを作成していく際は，まず，ロボット全体の中心となる *base_link* という名前のリンクを作成しましょう．このリンクのみ，必須のリンクになっています．任意のリンクをbase_linkに設定できますが，移動ロボットであれば重心があるリンク，アームロボットであれば環境と接続して動かないリンク，ヒューマノイドロボットであれば腰（胸）のリンクに設定すると良いでしょう．次に，base_linkにつながるジョイントを作成し，その次に作成したジョイントに接続するリンクを作成し・・というように，次々にリンクをつなげます．

```xml:gaze_arm.urdf
<?xml version="1.0"?>
<robot name="gaze_arm">

  <link name="base_link">
  </link>

  <joint name="joint0" type="fixed">
    <parent link="base_link"/>
    <child link="link1"/>
    <origin xyz="0 0 0.088" rpy="0 0.523594667 0" />
  </joint>

  <link name="link1">
  </link>

  <joint name="joint1" type="revolute">
    <parent link="link1"/>
    <child link="link2"/>
    <origin xyz="0 0 0.086" rpy="0 0 0" />
    <axis xyz="0 1 0" />
    <limit lower="-1.57" upper="1.57" effort="0.5293" velocity="6.159937255" />
    <friction friction="0.01" />
    <dynamics damping="0.4" />
  </joint>

  <link name="link2">
  </link>

  <joint name="joint2" type="revolute">
    <parent link="link2"/>
    <child link="link3"/>
    <origin xyz="0 0 0.06" rpy="0 0 0" />
    <axis xyz="1 0 0" />
    <limit lower="-1.046666667" upper="1.046666667" effort="0.5293" velocity="6.159937255" />
    <dynamics damping="0.4" />
  </joint>

 <link name="link3">
  </link>

  <joint name="camera_joint" type="fixed">
    <parent link="link3"/>
    <child link="camera_link"/>
    <origin xyz="0.015 0 0.025" rpy="0 0 0" />
  </joint>

 <link name="camera_link">
  </link>

</robot>

```

　URDFを作成したら，

$ check_urdf *gaze_arm.urdf*

として，作成したURDFが正しいフォーマットになっているかどうかチェックできます．コマンドがインストールされていない場合は，

$ sudo apt-get install liburdfdom-dev 

としてインストールしてください．
![check_urdf](https://pbs.twimg.com/media/B7UZu3mCYAEGRDn.png "check_urdf")
　また，

$ urdf_to_graphiz *gaze_arm.urdf*

とすることで，作成したURDFが見やすい形でPDFに出力されます．

　この時点で，

$ roslaunch urdf_tutorial display.launch model:= *gaze_arm.urdf*

とすると，rvizというROSのビジュアライザで，関節構造が3D表示されます．それぞれのジョイント部分の座標軸について，x軸，y軸，z軸がそれぞれ，赤，緑，青の棒で視覚化されます．
![rviz1](https://pbs.twimg.com/media/B7UV5HFCIAAj22a.png "rviz1")

## ビジュアルパラメータ
　ジョイントの座標軸表示だけだと面白くないので，視覚的にわかりやすいようリンクにビジュアルを設定しましょう．

### &lt;visual&gt;
　この要素の中に， **origin** ， **geometry** ， **material** といった要素を定義します．

#### &lt;origin xyz=" *xyz_val* " rpy=" *rpy_val* "&gt;
　 *xyz_val* のところには，根元のジョイントの位置を原点を基準とした，xyz距離[m]を入れてください．base_linkの場合は，座標系の原点になります． *rpy_val* のところには，リンクを回転させる角度を入力してください．

#### &lt;geometry&gt;
　このタグの中には，
> &lt;box size="1 1 1" /&gt;
> &lt;cylinder radius="1" length="0.5"/&gt;
> &lt;sphere radius="1"/&gt;
> &lt;mesh filename="mesh.dae" scale="1."/&gt;

といったタグで，形状を定義することができます．URDFで推奨されているメッシュのフォーマットは，Colladaの.dae形式です．STL形式も，一応サポートされています．

#### &lt;material&gt;
　このタグの中には，
> &lt;color rgba="0 0 .8 1" /&gt;
> &lt;texture filename="texture.png" /&gt;

といったタグで，表面の見栄えを定義することができます．


　先ほどのURDFにビジュアルパラメータを追加したURDFは，以下のようになります．

```xml:gaze_arm.urdf
<?xml version="1.0"?>
<robot name="gaze_arm">

  <link name="base_link">
    <visual>
      <origin xyz="0 0 0.044" rpy="0 0 0" />
      <geometry>
        <cylinder radius="0.015" length="0.088" />
      </geometry>
      <material name="blue">
        <color rgba="0 0 .8 1" />
      </material>
    </visual>
  </link>

  <joint name="joint0" type="fixed">
    <parent link="base_link"/>
    <child link="link1"/>
    <origin xyz="0 0 0.088" rpy="0 0.523594667 0" />
  </joint>

  <link name="link1">
    <visual>
      <origin xyz="0 0 0.035" rpy="0 0 0" />
      <geometry>
        <cylinder radius="0.01" length="0.065" />
      </geometry>
      <material name="blue" />
    </visual>
  </link>

  <joint name="joint1" type="revolute">
    <parent link="link1"/>
    <child link="link2"/>
    <origin xyz="0 0 0.086" rpy="0 0 0" />
    <axis xyz="0 1 0" />
    <limit lower="-1.57" upper="1.57" effort="0.5293" velocity="6.159937255" />
    <friction friction="0.01" />
    <dynamics damping="0.4" />
  </joint>

  <link name="link2">
    <visual>
      <origin xyz="0 0 0.005" rpy="0 0 0" />
      <geometry>
        <box size="0.015 0.045 0.05" />
      </geometry>
      <material name="green">
        <color rgba="0 .8 0 1" />
      </material>
    </visual>
  </link>

  <joint name="joint2" type="revolute">
    <parent link="link2"/>
    <child link="link3"/>
    <origin xyz="0 0 0.06" rpy="0 0 0" />
    <axis xyz="1 0 0" />
    <limit lower="-1.046666667" upper="1.046666667" effort="0.5293" velocity="6.159937255" />
    <dynamics damping="0.4" />
  </joint>

  <link name="link3">
    <visual>
      <origin xyz="0 0 -0.005" rpy="0 0 0" />
      <geometry>
        <box size="0.045 0.015 0.05" />
      </geometry>
      <material name="orange">
        <color rgba="1 .64 0 1" />
      </material>
    </visual>
  </link>

  <joint name="camera_joint" type="fixed">
    <parent link="link3"/>
    <child link="camera_link"/>
    <origin xyz="0.015 0 0.025" rpy="0 0 0" />
  </joint>

 <link name="camera_link">
    <visual>
      <origin xyz="0 0 0.0125" rpy="0 0 0" />
      <geometry>
        <box size="0.05 0.045 0.025" />
      </geometry>
      <material name="red">
        <color rgba=".8 0 0 1" />
      </material>
    </visual>
  </link>

</robot>

```

　check_urdfで，URDFが壊れていないことを確認しましょう．また，

$ roslaunch urdf_tutorial display.launch model:= *gaze_arm.urdf*

として，rvizで見栄えを確認してください．
![rviz2](https://pbs.twimg.com/media/B7UV5JACAAAer9J.png "rviz2")

## 物理パラメータ
　リンクには干渉と慣性のパラメータを，ジョイントには摩擦とダンピング抵抗の値を定義することができます．

### &lt;collision&gt;
　link要素の中に記述します．この要素の中に， **origin** ， **geometry** といった要素を定義します．これらの要素は，visual要素で指定したものと同様に定義します．

### &lt;inertial&gt;
　link要素の中に記述します．この要素の中に， **origin** ， **mass** ， **inertia** といった要素を定義します．定義方法は，記述例を参照してください．

### &lt;inertial&gt;
　joint要素の中に記述します．この要素の中に， **damping** ， **friction** といった要素を定義します．定義方法は，[こちら](http://wiki.ros.org/urdf/XML/joint)を参照してください．

　物理パラメータを追記したURDFは以下のようになります．

```xml:gaze_arm.urdf
<?xml version="1.0"?>
<robot name="gaze_arm">
  <link name="base_link">
    <visual>
      <origin xyz="0 0 0.044" rpy="0 0 0" />
      <geometry>
        <cylinder radius="0.015" length="0.088" />
      </geometry>
      <material name="blue">
        <color rgba="0 0 .8 1" />
      </material>
    </visual>

    <collision>
      <origin xyz="0 0 0.044" rpy="0 0 0" />
      <geometry>
        <cylinder radius="0.015" length="0.088" />
      </geometry>
    </collision>

    <inertial>
      <origin xyz="0 0 0.044" rpy="0 0 0" />
      <mass value="0.03" />
      <inertia ixx="1.0" ixy="0.0" ixz="0.0"
                         iyy="1.0" iyz="0.0"
                                   izz="1.0" />
    </inertial>
  </link>

  <joint name="joint0" type="fixed">
    <parent link="base_link"/>
    <child link="link1"/>
    <origin xyz="0 0 0.088" rpy="0 0.523594667 0" />
    <axis xyz="0 1 0" />
  </joint>

  <link name="link1">
    <visual>
      <origin xyz="0 0 0.035" rpy="0 0 0" />
      <geometry>
        <cylinder radius="0.01" length="0.065" />
      </geometry>
      <material name="blue" />
    </visual>

    <collision>
      <origin xyz="0 0 0.035" rpy="0 0 0" />
      <geometry>
        <cylinder radius="0.01" length="0.065" />
      </geometry>
    </collision>

    <inertial>
      <origin xyz="0 0 0.035" rpy="0 0 0" />
      <mass value="0.03" />
      <inertia ixx="1.0" ixy="0.0" ixz="0.0"
                         iyy="1.0" iyz="0.0"
                                   izz="1.0" />
    </inertial>
  </link>

  <joint name="joint1" type="revolute">
    <parent link="link1"/>
    <child link="link2"/>
    <origin xyz="0 0 0.086" rpy="0 0 0" />
    <axis xyz="0 1 0" />
    <limit lower="-1.57" upper="1.57" effort="0.5293" velocity="6.159937255" />
    <dynamics damping="0.4" friction="0.1" />
  </joint>

  <link name="link2">
    <visual>
      <origin xyz="0 0 0.005" rpy="0 0 0" />
      <geometry>
        <box size="0.015 0.045 0.05" />
      </geometry>
      <material name="green">
        <color rgba="0 .8 0 1" />
      </material>
    </visual>

    <collision>
      <origin xyz="0 0 0.005" rpy="0 0 0" />
      <geometry>
        <box size="0.015 0.045 0.035" />
      </geometry>
    </collision>

    <inertial>
      <origin xyz="0 0 0.005" />
      <mass value="0.04" />
      <inertia ixx="1.0" ixy="0.0" ixz="0.0"
                         iyy="1.0" iyz="0.0"
                                   izz="1.0" />
    </inertial>
  </link>

  <joint name="joint2" type="revolute">
    <parent link="link2"/>
    <child link="link3"/>
    <origin xyz="0 0 0.06" rpy="0 0 0" />
    <axis xyz="1 0 0" />
    <limit lower="-1.046666667" upper="1.046666667" effort="0.5293" velocity="6.159937255" />
    <dynamics damping="0.4" friction="0.1" />
  </joint>

  <link name="link3">
    <visual>
      <origin xyz="0 0 -0.005" rpy="0 0 0" />
      <geometry>
        <box size="0.045 0.015 0.05" />
      </geometry>
      <material name="orange">
        <color rgba="1 .64 0 1" />
      </material>
    </visual>

    <collision>
      <origin xyz="0 0 -0.005" rpy="0 0 0" />
      <geometry>
        <box size="0.045 0.015 0.05" />
      </geometry>
    </collision>

    <inertial>
      <origin xyz="0 0 -0.005" rpy="0 0 0" />
      <mass value="0.04" />
      <inertia ixx="1.0" ixy="0.0" ixz="0.0"
                         iyy="1.0" iyz="0.0"
                                   izz="1.0" />
    </inertial>
  </link>


  <joint name="camera_joint" type="fixed">
    <parent link="link3"/>
    <child link="camera_link"/>
    <origin xyz="0.015 0 0.025" rpy="0 0 0" />
  </joint>

  <link name="camera_link">
    <visual>
      <origin xyz="0 0 0.0125" rpy="0 0 0" />
      <geometry>
        <box size="0.05 0.045 0.025" />
      </geometry>
      <material name="red">
        <color rgba=".8 0 0 1" />
      </material>
    </visual>

    <collision>
      <origin xyz="0 0 0.0125" rpy="0 0 0" />
      <geometry>
        <box size="0.05 0.045 0.025" />
      </geometry>
    </collision>

    <inertial>
      <origin xyz="0 0 0.0125" rpy="0 0 0" />
      <mass value="0.04" />
      <inertia ixx="1.0" ixy="0.0" ixz="0.0"
                         iyy="1.0" iyz="0.0"
                                   izz="1.0" />
    </inertial>
  </link>

</robot>

```

$ roslaunch urdf_tutorial display.launch model:= *gaze_arm.urdf* gui:=True

ここで上記のように，rvizの起動時にguiパラメータにTrueをわたしてやると，GUIで関節をぐりぐり動かすことができるようになります．
![rviz3](https://pbs.twimg.com/media/B7UV5JGCYAAyO8b.png "rviz3")

## Gazebo用パラメータ
　さてさて，Gazeboで物理シミュレーションを行うためには，まだいくつかのパラメータを追加する必要があります．

　まずやらなければいけないのが，Gazebo用の特別なリンクの定義です．
### &lt;link name="world"&gt;
　worldという名前のリンクを，robot要素の最初に記述してください．
### &lt;joint name="world_joint" type="fixed"&gt;
　次に，world_jointという名前のリンクで，worldリンクとbase_linkの間を接続してください．今回はロボットアームで根元が地面に固定されているのでリンクタイプをfixedにしましたが，台車型の場合はplanar，その他の場合はfloatingなど，ロボットのタイプに合わせてリンクタイプを選択してください．

### &lt;transmission name=" *transmission_name* "&gt;
　稼働関節のシミュレーションを行うため，transmissionの要素を追加します．この要素は稼働関節ごとに一つ作成し，それぞれの関節がどのようなタイプのアクチュエータで駆動されているのかを定義します．詳しくは[こちら](http://wiki.ros.org/urdf/XML/Transmission)を参照してください．

### &lt;gazebo reference=" *link_name* "&gt;
　 *link_name* で指定したリンクにGazebo用のパラメータを追加します．主に行うのは，見栄えの材質の設定と，センサーの設定になります．記述例を参照してください．

### &lt;gazebo&gt;
　ロボットとGazeboを接続するプラグインを設定します．必ず必要です．

　以上の要素を追加したURDFが[こちら](https://github.com/yoneken/gaze_arm/blob/master/urdf/gaze_arm.urdf)になります．

　ROSのソースディレクトリで

$ wstool set --git gaze_arm https://github.com/yoneken/gaze_arm.git
$ wstool update gaze_arm

として，

$ catkin_make_isolated --install --pkg gaze_arm

でビルドしてください．その後，

$roslaunch gaze_arm test_urdf.launch

で，Gazeboが起動します．お疲れさまでした！これでロボットを物理シミュレータでテストすることができるようになりました♪

## xacro
　前章までで，やりたいことは全てできるようになりました．
　この章は，URDFの記述を少しだけ楽にする，拡張書式の話なので，そこまで重要ではありません．既に集中力が限界であれば，また気が向いたときに読んでもらえばOKです．
　xacroというのは，URDFの記述に

- 定数
- 数式
- マクロ

を導入することで，URDFの記述を少しだけ楽にすることができます．最終的に出力されるのはURDFなので，URDFの書き方さえマスターしていれば，xacroは無視して使う必要はないです．

### xacro書式の宣言
　robot要素に，
> &lt;robot xmlns:xacro="http://www.ros.org/wiki/xacro" name="firefighter"&gt;

のように，xmlns:xacroの項目を入れることで，xacro書式が有効にななります．

### 定数
> &lt;xacro:property name="pi" value="3.1415926535897931" /&gt;

　上記のようにpiという定数を宣言した場合，URDFのなかで， **${pi}** のように記述して，その定数を使用することができるようになります．

### 数式
　xacro書式では， **${}** で囲まれた中では， **${pi/6.}** といったように，数式による記述が可能となります．

### マクロ
> &lt;xacro:macro name="default_inertial" params="mass origin_xyz"&gt;

　上記のように，引数付きのマクロを利用することができるようになります．詳細については，[こちら](http://wiki.ros.org/urdf/Tutorials/Using%20Xacro%20to%20Clean%20Up%20a%20URDF%20File)を．具体的な利用方法については，先ほどのURDFを[xacro形式で書き直したもの](https://github.com/yoneken/gaze_arm/blob/master/urdf/gaze_arm.urdf.xacro)を参照してください．

# まとめ
- ROS勉強用のロボットを安価に作った．
- ロボットの関節軸構成は，URDFというフォーマットで記述できる．
- xacroというURDFの拡張書式がある．