ROS2講座12 ydlidarX4を使う

# 環境

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

| 項目 |	値 |
|:--|:--|
| CPU | Core i5-8250U |
| Ubuntu | 22.04 |
| ROS2 | Humble |

# 概要
LIDARはロボットでよく使われるセンサーの1つで、距離が高精度に分かるために特に移動ロボットで重宝されます。しっかりしたものはWebカメラなどに比べると高価でしたが、最近中国製の安価な物が発売されています。今回は1万円台の`YDLIDAR X4`を使ってみます。
![YDLIDAR.png](https://qiita-image-store.s3.amazonaws.com/0/254442/5dd6aa47-9f88-1ef8-55cc-35eec4a7704f.png)
[YDLIDARのwebサイト](https://www.ydlidar.com/products/view/5.html)より

## X4の購入
[switch science](https://www.switch-science.com/products/5412)で16,000円ほどで買えます。
最近はAmazonでも購入できます。Aliexpressでも少し安く購入できます。

# 梱包・内容物
内容物は以下です。

* YDLIDAR本体
* USB変換基板(+ケーブル)
* 予備モーターベルト
* USBケーブル
* 固定用ねじ（M2.3）x5
* 合格証

![YDLIDAR中身.JPG](https://qiita-image-store.s3.amazonaws.com/0/254442/34755bce-d568-1e7d-6de0-5d31a53f06c5.jpeg)

YDLIDAR本体には6ピンのシリアルインターフェイスしかありません。変換基板経由でUSBアクセスできます。

# 接続&udev追加

変換基板にはUSB microBコネクタがついていますが、片方は電力専用です。X4の消費電力が1ポートで出せる電力ギリギリの様で、接続する機器やUSBハブの有無によってモーター始動時に電源が落ちることがあります。
セルフパワーのUSBハブを使うなり、追加の電源を電力専用のUSBにつなぎましょう。

UbuntuPCにUSB接続が出来ると`/dev/ttyUSB0`として見えます。このままでも使えますが、別のデバイスとの兼ね合いで名前が変わってしまうので、udevにルールを追加します。以下のファイルを作成します。

```text:/etc/udev/rules.d/99-ydlidar.rules 
KERNEL=="ttyUSB*", ATTRS{idVendor}=="10c4", ATTRS{idProduct}=="ea60", MODE:="0666", GROUP:="dialout",  SYMLINK+="ydlidar"
```

SiliconLabのCP210xをYdlidarX4を区別する手掛かりにしています。これでYdLidarX4をつなぐと`/dev/ydlidar`と見えます。

# ROSと接続(on Ubuntu)

## YdliderSDKのインストール
ydlidarX4のドライバーノードをビルドするには、ライブラリであるYdlidarSDKのビルドとインストールが必要です。
以下のコマンドを実行してください。`/usr/local`以下にファイルが置かれます。

```shell:YdlidarSDKのインストール
cd /tmp
git clone https://github.com/YDLIDAR/YDLidar-SDK.git
cd YDLidar-SDK/
cmake -B build
sudo cmake --install build
```

## ros2driverの準備

公式のROS2のROSノードがあります。~~ただし最新のHumbleに対応していなく手直しが必要です。~~
masterブランチはまだROS2 Humbleに対応していなく、'humble'ブランチにcheckoutが必要です
(2023年8月に本家レポジトリでhumbleブランチが追加されました)。

* [YDLIDAR本家リポジトリ](https://github.com/YDLIDAR/ydlidar_ros2_driver)
`git clone git@github.com:YDLIDAR/ydlidar_ros2_driver.git -b humble`でブランチをcloneできます。

### 起動の準備

```python:ydlidar_ros2_driver/launch/X4_for_srs.launch.py(Forkリポジトリで追加したファイル)
#!/usr/bin/python3

from launch import LaunchDescription
from launch_ros.actions import Node
from ament_index_python.packages import get_package_share_directory
import os

def generate_launch_description():

    return LaunchDescription([
        Node(package='ydlidar_ros2_driver',
             executable='ydlidar_ros2_driver_node',
             namespace='/device/front_laser',
             output='screen',
             emulate_tty=True,
             parameters=[os.path.join(
                 get_package_share_directory('ydlidar_ros2_driver'), 'params', 'X4_for_srs.yaml')],
             )
    ])
```

```yaml:ydlidar_ros2_driver/params/X4_for_srs.yaml
/**:
  ros__parameters:
    port: /dev/ydlidar
    frame_id: front_laser_link
    ignore_array: ""
    baudrate: 128000
    lidar_type: 1
    device_type: 0
    sample_rate: 5
    abnormal_check_count: 4
    fixed_resolution: true
    reversion: true
    inverted: true
    auto_reconnect: true
    isSingleChannel: false
    intensity: false
    support_motor_dtr: true
    angle_max: 180.0
    angle_min: -180.0
    range_max: 12.0
    range_min: 0.1
    frequency: 10.0
    invalid_range_is_inf: false
    intensity_bit: 8
```

paramファイルでは以下のパラメーターを設定します。

| param名 | 説明 | X4での設定値 |
|:-:|:-:|:-:|
| frame_id | 出力するscanトピックのframe_idの値 | (ユーザー指定値) |
| ignore_array | 特定の範囲のデータを無視する | ""(空白) |
| baudrate | YdlidarX4とのUARTのbaudrate | 128000 |
| lidar_type | 測距方式 | 1(TYPE_TRIANGLE) |
| device_type | デバイスとの通信方式 | 0(YDLIDAR_TYPE_SERIAL) |
| sample_rate | x1000した値が1秒間に測距する点数(X4は5固定) | 5 |
| abnormal_check_count | エラーチェックの閾値 | 4 |
| fixed_resolution | 1scanでのデータ数が一定になるように補正するか | true |
| reversion | 出力をZ軸で180deg回転、falseだとmotorがある側がX軸になる | true |
| inverted | 出力がX軸で180deg回転、LIDARを上下逆に取り付けた時に変更 | true |
| auto_reconnect | 接続断で自動接続するか | true |
| isSingleChannel | 通信プロトコルに関わる値? | false |
| intensity | intensity出力を使用するか(X4はintensity非対応) | false |
| support_motor_dtr | DTRをモーター制御で使用するか | true |
| angle_max | 有効な角度範囲(これを超えた値はinvalid_range_is_infで決まる値に上書きされる) | 180 |
| angle_min | 有効な角度範囲(々) | -180 |
| range_max | 有効な距離範囲(々) | 12.0 |
| angle_min | 有効な距離範囲(々) | 0.1 |
| frequency | 測距デバイスの回転速度(X4では未サポート) | 10  |
| invalid_range_is_inf | 無効な測距値の値の指定 false:0, true:inf | true |


# ビルド&実行

```shell:ビルド
source /opt/ros/humble/setup.bash
cd ros2_ws
colcon build
```

```shell:実行
ros2 launch ydlidar_ros2_driver X4_for_srs.launch.py
```

![ydlidar_rviz.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/254442/49c97c9c-55f3-00e5-3390-3e0f185a8e33.png)

* コマンドを打つとYDLIDARが回転を始めます。`/device/ydlidar/scan`トピックで情報を見ることができます。
* Rviz2でも「LaserScan」のdisplayプラグインで観測情報を見ることが出来ます。Publisher側でQoSがBestEffortに設定されているため、Rviz側でも「Topic」の「Reliability Policy」を「Best Effort」に設定する必要があります。

# 参考
[$99と$400のLIDAR（360度レーザー距離測定機）を動かしてみた](http://asukiaaa.blogspot.com/2018/06/99400lidar360.html)

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