⚙️

YDLIDAR SDM15のPythonとarduinoライブラリを作った

2023/11/02に公開
9

はじめに

YDLIDAR SDM15のPythonとarduinoライブラリを作りました。

https://github.com/being24/YDLIDAR-SDM15_python
https://github.com/being24/YDLIDAR-SDM15_arduino

このライブラリは?

公式のマニュアルを参考に、SDM15をシリアル通信を用いて接続するライブラリです。

Python版ではpyserialを使用しています。

Python版ではマニュアルに記載されているすべてのコマンドを実装しています。
また、設定のパラメータはEnumで定義しているので、コード補完が効きます。

Arduino版ではArduino R4上でHardwareSerialでの動作確認をしています。
自分が使う一部のコマンドだけを実装した状態で止まっていたのですが、Python版のissueにArduino版無い?って聞かれたので暫定公開しました。
少なくともうちのロボットでは動いています。

使い方

from SDM15 import SDM15, BaudRate

if __name__ == "__main__":
    lidar = SDM15("/dev/ttyUSB0", BaudRate.BAUD_460800) # change the port name to your own port

    version_info = lidar.obtain_version_info()
    print("get version info success")

    lidar.lidar_self_test()
    print("self test success")

    lidar.start_scan()

    while True:
        try:
            distance, intensity, disturb = lidar.get_distance()
            print(f"distance: {distance}, intensity: {intensity}, disturb: {disturb}")
        except KeyboardInterrupt:
            break

ポートとBaudRateを指定して、SDM15のインスタンスを作成します。

その後、obtain_version_infoでバージョン情報を取得し、lidar_self_testでセンサの自己診断を行います。

start_scanで計測を開始し、get_distanceで計測結果を取得します。

#include "SDM15.h"

SDM15 sdm15(Serial1);

void setup() {
  pinMode(LED_BUILTIN, OUTPUT);
  Serial.begin(9600);
  Serial1.begin(460800);

  // wait 1s
  delay(5000);

  Serial.println("get data");

  // get version info
  VersionInfo info = sdm15.ObtainVersionInfo();

  if (info.checksum_error) {
    Serial.println("checksum error");
    return;
  }

  // print version info
  Serial.print("model: ");
  Serial.println(info.model);
  Serial.print("hardware_version: ");
  Serial.println(info.hardware_version);
  Serial.print("firmware_version_major: ");
  Serial.println(info.firmware_version_major);
  Serial.print("firmware_version_minor: ");
  Serial.println(info.firmware_version_minor);
  Serial.print("serial_number: ");
  Serial.println(info.serial_number);

  // get self check test
  TestResult test = sdm15.SelfCheckTest();

  if (test.checksum_error) {
    Serial.println("checksum error");
    return;
  }

  if (test.self_check_result) {
    Serial.println("self check success");
  } else {
    Serial.println("self check failed");
    Serial.print("error code: ");
    Serial.println(test.self_check_error_code);
    return;
  }

  delay(1000);
}

void loop() {
  // set output freq
  // bool result2 = sdm15.SetOutputFrequency(Freq_100Hz);
  // if (!result2) Serial.println("set output freq checksum error");

  Serial.println("start scan");

  // start scan
  bool result = sdm15.StartScan();

  if (!result) Serial.println("start scan checksum error");

  // get scan data 50 times
  for (int i = 0; i < 50000; i++) {
    ScanData data = sdm15.GetScanData();

    if (data.checksum_error) Serial.println("checksum error");

    Serial.print("scan times: ");
    Serial.print(i);
    Serial.print(" distance: ");
    Serial.print(data.distance);
    Serial.print(" intensity: ");
    Serial.print(data.intensity);
    Serial.print(" disturb: ");
    Serial.println(data.disturb);
  }

  // stop scan
  result = sdm15.StopScan();

  if (!result) Serial.println("stop scan checksum error");

  Serial.println("stop scan");

  // wait 1s
  delay(1000);

  exit(0);
}

Arduino版では、SDM15.hをインクルードして、SDM15のインスタンスを作成します。

その後、ObtainVersionInfoでバージョン情報を取得し、SelfCheckTestでセンサの自己診断を行います。

StartScanで計測を開始し、GetScanDataで計測結果を取得します。

Tips

  • Scan中は、stop_scanで計測を停止するか、get_distanceを呼び出すことしかできません。設定などを変更したい場合は、stop_scanで計測を停止してから行ってください。
  • 設定変更後はセンサを再起動することをおすすめします。Baud rateの設定は再起動しなければ反映されませんし、その他の設定変更もその後の通信が不安定になることがあります。
  • このセンサはstart_scanを呼び出さなければ計測を開始しません。
  • 開発マニュアルには、このセンサを使用するときは以下の手順を踏むことを推奨しています。
    • まずobtain_version_infoでバージョン情報を取得する
    • 次にlidar_self_testでセンサの自己診断を行う
    • 最後にstart_scanで計測を開始する
  • python版のライブラリは、atexitを使用してプログラム終了時にstop_scanを呼び出したあとにシリアルポートを自動的に閉じます。

愚痴

SDM15はBaudRateを230400、460800、512000、921600、1500000から選択できます。
しかしながら、SDM15用に案内されているUSB-UART変換モジュールはCP2102を採用しており、センサで使用できる選択肢は230400、460800、921600のみであるため、512000、1500000は使用できません。
ライブラリ開発中にBaudRateを1500000に設定したところセンサとの通信ができなくなり、FT231Xを引っ張り出す羽目になりました。
付属品みたいなものなのに、センサのBaudRateに対応できないのは勘弁してほしい……。

GitHubで編集を提案

Discussion

KikiyKikiy

わかりやすい記事ありがとうございます。
こちらの記事のおかげでarduino unoのTX,RXポートで動作ができました。
2つ質問があります。
1.センサを2つ同時に使いたいのですが、arduino unoのソフトウェアシリアルでTX、RXが使えません。。どのような方法(スケッチ)をすればよいのでしょうか?
2.arduino megaではセンサを認識してくれませんでした。方法はありますでしょうか?

beingbeing

現在のコードはHardwareSerialを指定しているので、SoftwareSerialでは使用できません。SDM15.hの

explicit SDM15(HardwareSerial &serial) : _sensor_serial(serial) {}

explicit SDM15(Stream &serial) : _sensor_serial(serial) {}

に、また、

HardwareSerial &_sensor_serial;

Stream &_sensor_serial;

に変更すると動くかもしれませんが、確認はしていません
なにかエラー出たら教えてください

arduino megaのハードウエアシリアルで動作を確認してみましたが、こちらでも認識してくれませんでした。手が空き次第確認します。

KikiyKikiy

前回はご回答いただき感謝しております。
やはりmegaでは動いてくれないのですが(ちなみにunoでも動きません)、ボーレートが460800なのが問題なのでしょうか?ボーレートを230400に下げる方法?(プログラム)で試したいのですが、hファイルなど全然わかりません。。教えていただくことは可能でしょうか?
またまた恐縮ですが、前回教えていただいたソフトウェアシリアルですが、hファイルを書き換えて上書き保存したのですが、元のプログラムの変更点なども追記いただけると助かります。
すみません。。

beingbeing

返信遅れて申し訳ないです

baudrateを下げるには、

  1. 接続できている状態で、sdm15.SetBaudRate(BAUD_230400)を実行しセンサを再起動
  2. YDLIDAR-SDM15_arduino.inoのSerial1.begin(230400);の数字部分を設定し、プログラムをbuild
    で可能なはずです
KikiyKikiy

ありがとうございます。早速ためしてみます。

KikiyKikiy

すみません。
// bool result2 = sdm15.SetOutputFrequency(Freq_100Hz);
ここをチェックアウトして書き込んだところ、センサが反応しなくなってしまいました。
復帰できるすべはありますでしょうか?

beingbeing

状況を正確に判断できていませんが、センサ自体の再起動(電源線を外してつけ直すなど)をした上で再実行しても状態は変わりませんでしょうか?

正直arduinoでデバッグするのは大変なので、python版で試してみることをおすすめします。

もしくはTX、RXにオシロスコープやロジックアナライザをつないで出力を見てみるなども有効かと思います

KikiyKikiy

早々にお返事いただき感謝しております。
ご指示いただいた内容で試してみます。
ありがとうございます。

KikiyKikiy

kikiy様
arduinoR4で2台同時に使用したいのです。ソフトウェアシリアル(myserial1とmyserial2)で使用するためのスケッチをお手数ですがご教示いただくことは可能でしょうか??
(SDM15.hを書き換えたのですがmyserialでは反応せず。。)