reTerminal(Raspberry Pi)でパトライト(NHL-3FB1)を動かしてみた

前回のブログからだいぶ間が空いてしまいました…

supernove.hatenadiary.jp

あれから仕事がクソ忙しくなりなかなかブログの更新もできずでしたが、肩慣らしにネタを用意しました。

先日これまた久々に大須パソコンショップパウさんに行ってきて、パトライトが売られてたのでつい買ってしまいました。型番はNHL-3FB1で値段はジャンク価格で3000円でした。

このパトライトは有線で接続することでそこからネットワーク監視をするために使われる機材らしくコマンドを送信することでライトだけではなくブザーを鳴らすこともできるすごいやつです。

これをジャンクで販売するパウさん、やばいですw。本体のみで販売してたのでおそらく詳細に動作確認する素手がないのでジャンクにしたのでしょう。Tweetに写り込んでるACアダプタは完全に社外品ですが、かごに絡まってるACアダプタから奇跡的に端子と出力電圧が合っているやつを引き当てました。(ライト側には電流の指定がなかったので多分問題なく動くでしょうw)

というわけで今回はこのパトライトをreTerminalで動かしてみました。

とりあえず動作テスト

まずはテストボタンがあったので適当に長押しして動作確認してみました。

ここで通電しないと何も始まりませんが、ここは問題なく通電してテストボタンもちゃんと機能しました。どうでもいいですがCLEARボタンの押し心地いいですw。

初期化する

問題なく動作することがわかったところで接続をしていきますが、その前にジャンクなので前に使っていた人の設定が残っていると原因の切り分けが面倒なのでここは工場出荷状態に初期化します。

NHL-3FB1の初期化はとても簡単で電源を落としている状態でVOL.スイッチをOFFにした状態でTESTボタンとCLEARボタンを同時押しして電源をいれます。

するとブザーを鳴らして初期化が始まります。ブザーが鳴り止んだら押してたボタンを離して初期化は完了です。

reTerminalで接続する

IPを割り当てる

それではreTerminalで接続していきます。

NHL-3FB1のIPアドレス192.168.10.1 です。これをブラウザで入力すれば接続できるのですが、機能上の制限でDHCPが機能しなくてIPを自動で割り当ててくれません。

というわけで接続前に同一のセグメントで固定IPを設定する必要があります。

Raspberry Piであれば /etc/dhcpcd.confに以下の設定を書き込めばNHL-3FB1に最低限接続できるようになります。( ip_address は複数使う場合は変更する必要があります)

interface eth0
fallback static_eth0

static ip_address=192.168.10.2/24
static routers=192.168.10.1
static domain_name_servers=192.168.10.1

あとは再起動すれば接続するための準備は完了です。

管理画面を開く

再起動したら、ブラウザで 192.168.10.1と入力すると管理画面を開けます。

初期状態ではパスワードは patlite を入力すると管理画面を開けます。

管理画面から 表示灯操作 を開くとブラウザで手軽にライトとブザーを動作できます。

コマンドで動かす

買ったときにその場でググったときにはHTTP通信ができる的な書き方してましたが、ファームウェアが古いせいでHTTP通信に対応してないようでした…

代わりにNCコマンドを使ってソケット通信で16進数を送信する方法を見つけたので、試していきます。

kooshin.hateblo.jp

この方法を試すには bc コマンドが必要ですがインストールされてないので、以下のコマンドでインストールしていきます。

sudo apt install bc

あとは参考記事にあるPHNコマンドを試しにやってみました

以下のコマンドは緑を点滅させてそれ以外をOFFにしてます。

echo -ne '\x57\x'$(echo "obase=16;ibase=2;10000000" | bc) | nc -q1 192.168.10.1 10000

さらに以下のコマンドで赤の点滅とブザーを鳴らすのを同時に実行できます。

echo -ne '\x57\x'$(echo "obase=16;ibase=2;00101000" | bc) | nc -q1 192.168.10.1 10000

もっと細かく操作するならPSNコマンドを使いますが、PSNコマンドを動かすだけでもアプリケーションに組み込んでいろいろできそうです。

まとめ

今回はジャンクのパトライトを買ったので、reTerminalでハックしてみました。

ネットワークの知識が乏しくて設定とか操作で苦戦しましたが、なんとか自由自在に操作できるぐらいまではできるようになったので十分かなと思います。

せっかくなので今度Ogaki Mini Maker Fairの見世物に持っていくためにいろいろ仕掛けてみようと思います!

Real VNC ServerをUbuntuにセットアップして別のネットワークからでも接続できるようにしてみた

転職して3ヶ月経ちましたが抱えている悩みがあります。

それはオフィスのデスクトップPCに家から接続したい。

出社がメインでオフィスではデスクトップPCを使って作業していますが、リモートワークもすることがありオフィスで作業した内容をコミットし忘れて作業が出来ないという課題がありました。

というわけでこの課題を解消するためにReal VNCを導入して別ネットワークから接続できるようにしてみました。

今回はUbuntuのデスクトップPCでのセットアップ方法を紹介します。

インストール

以下のサイトからReal VNC Serverをインストールファイルをダウンロードします。

www.realvnc.com

以下のコマンドでインストールします。

sudo dpkg -i ./VNC-Server-6.9.1-Linux-x64

依存パッケージをインストールします

sudo apt install libcanberra-gtk*

セットアップ

UbuntuVNC ServerをセットアップするにはReal VNCアカウントが必要です。

アカウントが無いときは以下のサイトから無料で作成できます。

https://manage.realvnc.com/en/

アカウント作成したらRealVNCを起動して画面の流れに沿ってセットアップしていきます。

基本的にはデフォルトの設定で進めればOKです。

これであとは接続するPCにVNC Viewerをインストールして右上からログインを行います。

ログインが完了し、先程のセットアップしたPCと接続できたら完了です。

ログアウト状態からでも接続できるようにする

このまま接続するのはいいのですが、PCを使わないときはログアウト状態が続きます。

Ubuntu 20.04だとデフォルトの設定ではログアウト状態が長続きするとスリープになってしまい、ネットワークも切断されます。

ocg.aori.u-tokyo.ac.jp

そこで↑を参考に以下のコマンドで自動スリープを無効にします。

sudo systemctl mask sleep.target suspend.target hibernate.target hybrid-sleep.target

これでログアウト状態のPCにいつでも接続できるようになります。

Raspberry Pi zero 2 w開封レビュー

先日奇跡的にRaspberry Pi zero 2 wをスイッチサイエンスで買えました。(ちなみに右側の赤いボードは送料ケチるために買ったシリアル変換アダプタです)

今回は外観やちょっとした比較をしてみたいと思います。

外観

インターフェースが初代のzero Wと変わらないこともあってパッと見は何も変わりませんが、CPUにRaspberry PiのロゴがあったりGPUヒートシンクが付いてるところは大きく違います。

手元にあったzero Wと比較するとこんな感じです。ある程度スペースに余裕があるケースであれば互換性がありそうなぐらいよく似てます。

今のところはピンヘッダが実装されてないので、GPIO使いたいときにはピンヘッダを何処かで買う必要があります。

火入れ

64ビットのCPUになったので、試しに64ビットのRaspberry Pi OSにインストールして動かしてみました。

初回の起動は多少遅いですが、なんとか動かせました。

あまりに長いのでマジで焦りましたw。

ベンチマーク

今度は性能がどんなもんなのか調べるためにベンチマークを採ってみます。

当然、zero 2 wだけで測定しても意味がないので比較のために今現在市場に出回ってなくもない以下の4台を比較してみます。

そしてベンチマークの測定には比較的簡単に使えるUnix Benchで軽く確認してみます。

以下のコマンドでインストール・実行します。

sudo apt install git
git clone https://github.com/kdlucas/byte-unixbench
cd byte-unixbench/UnixBench
./Run

上記コマンドをそれぞれのボードに対して行いました。その中から恣意的に選んだ5つの項目のIndex値についてグラフで出力しました。

各項目の内容はこんな感じです。(参考:https://blog.idcf.jp/entry/cloud/unixbench/)

  • Dhrystone 2 using register variables:整数演算処理の伝統的なベンチマークツール
  • File Copy:ファイルのコピー(ライト→リード)を繰り返すテスト
  • Pipe Throughput:データをパイプ処理しこれを繰り返し実行することでスループットをテストしている
  • Shell Scripts:sort、od、grep、tee、wcコマンドやパイプやリダイレクトを使ったテキスト処理を繰り返すテスト
  • System Call Overhead:プロセスIDを返す単純なシステムコールを繰り返し実行するテスト

そしてベンチマーク全体を通してのインデックススコアのグラフがこちらです。

やはりzero 2 Wは zero Wよりも圧倒的に性能が向上しているのはすごいですね!

まとめ

今回はRaspberry Pi zero 2 Wの動作確認も兼ねた開封レビューをしました。

Wifiは2.4GHzしか対応してなかったりしますがzero Wよりも多少性能が上がったので高度な処理を必要とするロボットに組み込むにはぴったりなんじゃないかなと思いました。

今のところ1個しかないのでもう1個入手したら今作っているロボットに組み込んでみてもいいのかなと思いました。

ROSで動かすロボットカー作り(きれいに地図を作成できるようにしてみた編)

前回はHector SLAMを使って地図が更新できるようにいろいろセットアップできるようにしてみました

supernove.hatenadiary.jp

ところが、ここで作成された地図は思ってたのと違う結果になってしまいどうしたことか…という状態でした。

そんな中久々にROS UG JPのLT大会があり、前回エントリーをネタにLTしてきました。

speakerdeck.com

このスライドをTwitterで投稿したら思いのほかバズって笑ってしまったのはここだけの話ですw。

で、そのツイートのリプに出力された地図がおかしい原因の解消に繋がりそうな有力情報がありました

それだぁぁーーーー!!!!

確かに言われて見れば地図を作成されるときってTFの座標系が表示されてそこから軌跡がrvizに出力されるはずなのにそんな様子がひとつもなかったんです。

というわけで、このリプをヒントに地図がきれいに生成されるように試してみました。(といっても頂いた記事の内容を参考にしただけですが…)

今回の成果物はいつもどおり以下のレポジトリのbacklog/step7ブランチで切っています。

github.com

mapping_default.launchの修正

以下の記事を参考にlauchファイルをいくつか修正していきます。

qiita.com

hector_slamディレクトリのhector_mapping/launch/mapping_default.launchのなかの5,6行目を修正します。

-  <arg name="base_frame" default="base_footprint"/>
-  <arg name="odom_frame" default="nav"/>
+  <arg name="base_frame" default="base_link"/>
+  <arg name="odom_frame" default="base_link"/>

そして54行目のコメントアウトを解除します。

-  <!--<node pkg="tf" type="static_transform_publisher" name="map_nav_broadcaster" args="0 0 0 0 0 0 map nav 100"/>-->
+  <node pkg="tf" type="static_transform_publisher" name="map_nav_broadcaster" args="0 0 0 0 0 0 map nav 100"/>

最終的に以下のようになっていれば大丈夫です。

<?xml version="1.0"?>

<launch>
  <arg name="tf_map_scanmatch_transform_frame_name" default="scanmatcher_frame"/>
  <arg name="base_frame" default="base_link"/>
  <arg name="odom_frame" default="base_link"/>
  <arg name="pub_map_odom_transform" default="true"/>
  <arg name="scan_subscriber_queue_size" default="5"/>
  <arg name="scan_topic" default="scan"/>
  <arg name="map_size" default="2048"/>
  
  <node pkg="hector_mapping" type="hector_mapping" name="hector_mapping" output="screen">
    
    <!-- Frame names -->
    <param name="map_frame" value="map" />
    <param name="base_frame" value="$(arg base_frame)" />
    <param name="odom_frame" value="$(arg odom_frame)" />
    
    <!-- Tf use -->
    <param name="use_tf_scan_transformation" value="true"/>
    <param name="use_tf_pose_start_estimate" value="false"/>
    <param name="pub_map_odom_transform" value="$(arg pub_map_odom_transform)"/>
    
    <!-- Map size / start point -->
    <param name="map_resolution" value="0.050"/>
    <param name="map_size" value="$(arg map_size)"/>
    <param name="map_start_x" value="0.5"/>
    <param name="map_start_y" value="0.5" />
    <param name="map_multi_res_levels" value="2" />
    
    <!-- Map update parameters -->
    <param name="update_factor_free" value="0.4"/>
    <param name="update_factor_occupied" value="0.9" />    
    <param name="map_update_distance_thresh" value="0.4"/>
    <param name="map_update_angle_thresh" value="0.06" />
    <param name="laser_z_min_value" value = "-1.0" />
    <param name="laser_z_max_value" value = "1.0" />
    
    <!-- Advertising config --> 
    <param name="advertise_map_service" value="true"/>
    
    <param name="scan_subscriber_queue_size" value="$(arg scan_subscriber_queue_size)"/>
    <param name="scan_topic" value="$(arg scan_topic)"/>
    
    <!-- Debug parameters -->
    <!--
      <param name="output_timing" value="false"/>
      <param name="pub_drawings" value="true"/>
      <param name="pub_debug_output" value="true"/>
    -->
    <param name="tf_map_scanmatch_transform_frame_name" value="$(arg tf_map_scanmatch_transform_frame_name)" />
  </node>
    
  <node pkg="tf" type="static_transform_publisher" name="map_nav_broadcaster" args="0 0 0 0 0 0 map nav 100"/>
</launch>

tutorial.launchの修正

続いて同じくhector_slamディレクトリのhector_slam_launch/launch/tutorial.launchuse_sim_timefalseにしてリアルタイム動作にします。

これで実機で問題なく地図が作成されるようになります。

<?xml version="1.0"?>

<launch>

  <arg name="geotiff_map_file_path" default="$(find hector_geotiff)/maps"/>

  <param name="/use_sim_time" value="false"/>

  <node pkg="rviz" type="rviz" name="rviz"
    args="-d $(find hector_slam_launch)/rviz_cfg/mapping_demo.rviz"/>

  <include file="$(find hector_mapping)/launch/mapping_default.launch"/>

  <include file="$(find hector_geotiff)/launch/geotiff_mapper.launch">
    <arg name="trajectory_source_frame_name" value="scanmatcher_frame"/>
    <arg name="map_file_path" value="$(arg geotiff_map_file_path)"/>
  </include>

</launch>

このファイルから先程修正したmapping_default.launchを呼び出していることがわかると思います。

hector_slam.launchの修正

最後にmy_roberのlaunchディレクトリ内の hector_slam.launchを先程修正した tutorial.launchを呼び出すように修正します。

  <!-- hector_slam -->
-  <include file="$(find hector_mapping)/launch/mapping_default.launch" />
-  <include file="$(find hector_geotiff)/launch/geotiff_mapper.launch">
-    <arg name="trajectory_source_frame_name" value="scanmatcher_frame"/>
-    <arg name="map_file_path" value="$(arg geotiff_map_file_path)"/>
-  </include>
+  <include file="$(find hector_slam_launch)/launch/tutorial.launch"/> 
  
</launch>

動作確認

それでは動作確認です。

以前用意したJoystickノードを使ってゲームパッドでロボットを動かすことで地図が作成されていきます。

このときJoystickノードから速度を配信するときにはなるべくゆっくりに設定するのがコツです。特にangular.zに関してはめちゃくちゃゆっくりにしないとちゃんと軌跡が描画されずTFの設定がちゃんとできてないときの汚い地図になります。

それに気をつけながら地図作成してみると、動画ではわかりにくいですがちゃんと軌跡に沿って空間情報が作成されていることが確認できます。

youtu.be

そして完成した地図です、前回とは比べ物にならないぐらいきれいな地図ができました!

まとめ

今回はHector SLAM できれいに地図が作成されるようにリベンジをしてきました。

ROSで位置、姿勢推定するうえでtfはかなり重要なキーワードで理解するのが大変ですが、これがわからないとSLAMが出来ないということに気付かされました。アドバイスくれたnisshan_ さん、ありがとうございました!

これでナビゲーションも順調に行ってくれるといいな…

BIOSパスワードのかかったThinkpadを突破してみた

その昔大学入学した頃何もPCの知識がないときに大学推奨PCを使っていました。

大学推奨のPCはクソスペックな上に値段も馬鹿みたいに高いです。

PCを買い替えてから今までずっと放置されていましたが、ついにそんなPCを手放しました。大須の佐古前装備さんで買取お願いしたら一応まだ動くこともあって意外といい値段付きました。

PCパーツやラップトップ売るなら佐古前装備さん超オススメです!

で手放す代わりにおなじみ大須のパウでジャンクのThinkpadを買いました(どうしてそうなったw)

お店にはいくつかジャンクのThinkpadがあって、こいつが一番見た目のダメージがひどくなかったので選びましたが、BIOSロックがかかっているのでPCのスペックを確認できないのがジャンク理由です。

ちなみに裏に張ってあったシール跡からどうやらIBMで昔業務用に使われていたものだったみたいです(Thinkpadは元々IBMが製造してましたもんね)。

ググってみたら工夫すればパスワードを突破できるみたいなので今回はこのBIOSパスワードを突破してみたいと思います。

用意するもの

  • Thinkpad x201i(パウで購入、メモリなし)
  • メモリ 2GB(PC3-8500)
  • ドライバー
  • 縫い針
  • ピンセット

まずは動作確認

試しに電源入れてみます。

BIOSがかかっているだけで通電は大丈夫でした。バッテリーもまだ生きてます。

とりあえず見た目の損傷もないしますます直しがいありますね。

突破法1:BIOSリセット

まずは本体を分解してCMOSボタン電池を外してみます。

キーボードを固定しているネジ(底面にキーボードのマークがあるところ)をはずしてキーボードを外せます。

黄色いカバーがついてるところがボタン電池です。つながっているコネクターを外してしばらく放電させてみます。

つなげ直して電源を入れましたが解除できませんでした。

というわけでこのThinkpadにはスーパーバイザーパスワード(SVP)がかかっているので今度はSVPを解除する方法を試します。

突破法2:針を刺してみる

SVPがかかっていることが分かったところで突破方法を試してみます。

なるべく分解したくないので針を使ってeepromの信号を乱してみます。

v2ndev.blog.fc2.com

↑の記事を参考に縫い針をピアに当てて起動を試みましたが何度やってもだめでした…

突破法3:eepromのi2cの信号ピンをショートさせる

針でうまく信号を乱せなかったのでeepromの信号ピン(SDA, SCL)をショートさせます。

eepromは基板を外す必要があるので、ハードウェア保守マニュアルをみながら外せるところを外して分解します。

分解するときは写真を撮っておくと安心です。

https://download.lenovo.com/pccbbs/mobiles_pdf/x200_x200s_x200si_x201_x201i_x201s_hmm_en_43y6632_11.pdf

SDA、SCLの位置は以下の記事を参考にしました

www.ja.axxs.net

SDAとSCLは隣り合わせみたいなのでピンセットを使って両方のピンをはさみます。

そして電源を入れると無事にSVPを突破してBIOSにアクセスできました!そして画面もきれいなので普通にOS突っ込めば問題なく使える状態になりました。

パスワードも無効になって一安心です。

キーボードの交換&OSインストール

というわけで分解したやつを元に戻してPCとして使える状態に戻りました。ここでよくありがちなネジの締め忘れでネジが余るという事態は起きませんでした(逆にネジを紛失して不足する事態もありませんでしたw)

無事に元の状態に組み上がったところで魔改造をします。僕はキーボードは英語配列派なので英語配列のキーボードに交換します(簡単にキーボードを交換できるという理由でThinkpadを買っています)。

キーボードはヤフオクで唯一売られてた新品を買いました。

そしてキーボードだけ無駄に新品のPCが出来上がりましたw。

そしてSSDを用意してOSをインストールします。

mSATAのSSDを使いたかったですが残念ながらこのモデルはストレージには対応してないっぽかったので普通に2.5インチのやつを使いました。

インストールするOSは例のごとくUbuntuです。

Ubuntu 20.04のインストールは慣れたもんです。

supernove.hatenadiary.jp

そして、無事にOSが立ち上がりました。

キーボードの反応も問題ないし無事にパスワードがかかってたPCが復活しました!

まとめ

今回はパスワードがかかったThinkpadを使えるようにしました。見た目もひどくないからこそこういうパターンはちょっとクセがありますが動かせるとかなり格安でPCを使えるようになるのでぜひ挑戦してみましょう!

まぁ今回はキーボードを交換したので余計お金かかりましたけどねw

ROSで動かすロボットカー作り(SLAMをできるようにしてみた編その2)

前回はgmappingを使ってSLAMをやろうとするところまでで終わりました

supernove.hatenadiary.jp

このブログの中では地図が更新されなくて多分机の上で動かすだけだと更新されないと思ってました。

が、これは大きな勘違いで正確にはodometryのデータを一つも用意してなかったのが原因です。

gmappingではロボットの移動距離の情報としてodometryをロボット側で配信する必要がありますが、それができてませんでした。

ただ、今作っているロボットにはロータリーエンコーダーとかを使ってモーターの回転数取れればいいのですが、なるべく楽したいのでLidarセンサーだけで地図を作成する方法を模索しました。

今回の成果物もいつも通り以下のレポジトリの backlog/chapter6ブランチで切っています。

github.com

用意するもの

前回と同様のものですが、一応載せておきます

動作環境

今回もRaspberry Pi上で試すのでRaspberry Piの動作環境を紹介します

LidarセンサーだけでSLAMをやる方法

ググったらいくつか候補が出てきたので試しました。

候補1:gmapping + laser_scan_matcher

gmapping単体だとodomデータが足りなくて地図が更新されませんが、laser_scan_matcherを使ってLidarのデータの変化量から移動距離を算出します。

sudonull.com

この方法ならセンサーを用意したり自分でロジックを書かなくても地図が更新されるようになるみたいです。

ただ、Raspberry Pi OSだとlaser_scan_matcherを使うために必要な依存パッケージが多いのとビルドエラーが出まくっているので今回は却下しました。

候補2:hector_slam

gmappingの代わりにhector_slamを使う方法が候補にありました。

これならodomデータがなくてもパッケージ単体で地図を生成できるらしいです。

試しに動かしてみたらセンサー単体を動かすだけでも簡単に地図を更新できるようになったので今回はこの方法で地図を生成してみました。

hector_slamをインストール

まずは依存パッケージをインストールします。

sudo apt install libflann-dev libeigen3-dev libglvnd-dev

ワークスペースディレクトリ直下のsrcディレクトリ内にhector_slamのソースコードをクローンします。

git clone https://github.com/tu-darmstadt-ros-pkg/hector_slam

ビルドを実行します。

catkin build

パッケージを追加したのでセットアップスクリプトを実行します。

source devel/setup.bash

これで必要な物は揃いました。gmappingのときと同じぐらい簡単にインストールが終わりました。

とりあえず動かしてみる

インストールはできたので試しに机の上でセンサーを動かしてみます。

今回は以下のlaunchファイルを使います。

ファイル名は hector_slam.launchとします。

<launch>

  <!-- X2L -->
  <node name="ydlidar_node"  pkg="ydlidar_ros"  type="ydlidar_node" output="screen" respawn="false" >
    <param name="port"         type="string" value="/dev/ydlidar"/>
    <param name="baudrate"         type="int" value="115200"/>
    <param name="frame_id"     type="string" value="base_link"/>
    <param name="resolution_fixed"    type="bool"   value="true"/>
    <param name="auto_reconnect"    type="bool"   value="true"/>
    <param name="reversion"    type="bool"   value="false"/>
    <param name="angle_min"    type="double" value="-180" />
    <param name="angle_max"    type="double" value="180" />
    <param name="range_min"    type="double" value="0.1" />
    <param name="range_max"    type="double" value="12.0" />
    <param name="ignore_array" type="string" value="" />
    <param name="frequency"    type="double" value="8"/>
    <param name="samp_rate"    type="int"    value="3"/>
    <param name="isSingleChannel"    type="bool"   value="true"/>
  </node>

  <!-- tf -->
  <node pkg ="tf" type="static_transform_publisher" name="map_to_odom" args="0.0 0.0 0.0 0.0 0.0 0.0 /map /nav 40"/>
  <node pkg ="tf" type="static_transform_publisher" name="odom_to_base_link" args="0.0 0.0 0.0 0.0 0.0 0.0 /nav /base_footprint 40"/>
  <node pkg="tf" type="static_transform_publisher" name="base_link_to_laser" args="0.2245 0.0 0.2 0.0 0.0 0.0 /base_footprint /base_link 40" />
  
  <!-- hector_slam -->
  <include file="$(find hector_mapping)/launch/mapping_default.launch" />
  <include file="$(find hector_geotiff)/launch/geotiff_mapper.launch" />
</launch>

gmappingのときは直でパラメータを指定してましたが、hector_slamではデフォルトで用意されているlaunchファイルを呼び出すようにしています。

ちなみに上記のlaunchファイルは以下の記事を参考にX2L向けにアレンジしました

archit0994.wixsite.com

実際に動かしてみます。

以下のコマンドでlaunchファイルを動かします。

roslaunch my_rober hector_slam.launch

そして可視化は以下のコマンドでrvizを起動します。(前回の同じ設定ファイルを読み込んでますが、他のSLAMパッケージでも使えるのでファイル名を変えてます)

rosrun rviz rviz -d $(find $(pwd) -name slam.rviz)

起動したらセンサーをいろいろ動かしてみるとそれに合わせて地図が更新されていることが確認できます。

navigationパッケージのセットアップ

無事に動作することが分かったところで実際に地図を作成していきます。

ただ今のままだとロボットを走らせて地図を作成してもその地図を保存する手段がありません。

地図を保存するためには navigationパッケージの map_serverを使用します。

そこで地図を作成する前にnavigationパッケージをセットアップしていきます。

まずは以下のコマンドで依存ライブラリをインストールします。

sudo apt install libbullet-dev libsdl-image1.2-dev libsdl-dev

ワークスペースディレクトリ直下のsrcディレクトリ上でnavigationパッケージとその依存パッケージをクローンします。

git clone -b melodic-devel https://github.com/ros-planning/navigation.git
git clone -b melodic-devel https://github.com/ros/geometry2.git
git clone -b ros1 https://github.com/ros-planning/navigation_msgs.git

ビルドを実行します。

catkin build

hector_slamと同様にセットアップスクリプトを実行します。

source devel/setup.bash

地図を作成する

いよいよ地図を作成していきます。

まずは以下の記事を参考にJoystickでロボットを動かす準備をします。

supernove.hatenadiary.jp

地図を作成する場所にロボットを設置したら以下のコマンドでマッピング用のノードを起動します

roslaunch my_rober hector_slam.launch

これでゲームコントローラーでロボットを操作しながら地図を作成します。

一通り地図を作成したら以下のコマンドで地図のデータを保存します。

 rosrun map_server map_saver

作成した地図はこんな感じです。

Lidarのみで作成しているだけに結構ぐちゃぐちゃした地図になってますね…

まとめ

今回はhector_slamを使ってSLAMに挑戦しました。

Lidarだけでマッピングできると思ってやってましたが、やっぱり急な方向転換に弱いせいか精度は今ひとつでしたね。

今度は精度の高い地図を作成するためにどうすればいいか試行錯誤していこうと思います。

ROSで動かすロボットカー作り(SLAMをできるようにしてみた編)

※最初に

このエントリーのオチはパッケージの僕の理解不足で地図が作成されませんでした。

とにかくてっとり速く動いたパッケージのセットアップ方法を知りたい方は以下のエントリーをどうぞ

supernove.hatenadiary.jp

以前Lidarセンサーを動かして無事にセンサーの情報を取得することができたので、今回はこのLidarセンサーを使ってSLAMをできるようにしてみます。

Lidarセンサーを試した記事はこちら

supernove.hatenadiary.jp

今回の成果物はいつものように以下のレポジトリの backlog/step5ブランチで切っています。

github.com

用意するもの

ロボットには他にもいくつかパーツ使っていますが、今回のブログで使う機材だけを紹介します

動作環境

今回はRaspberry Pi上で試すのでRaspberry Piの動作環境を紹介します

Gmappingのインストール

まずはSLAMに必要なパッケージをインストールします。

今回は最もメジャーなSLAMパッケージであるGmappingをインストールします。

ワークスペースディレクトリ直下のsrcディレクトリ内で以下のコマンドを実行してパッケージのソースコードをクローンしてきます。

cd rober_catkin_ws/src
git clone https://github.com/ros-perception/slam_gmapping

続いて、依存パッケージであるopenslam-gmappingも合わせてクローンします。

git clone https://github.com/ros-perception/openslam_gmapping.git

これで必要なパッケージのインストールができたので、ビルドします。

catkin build

エラーが出なければインストールは完了です。

lauchファイルの用意

続いてマッピング用のlaunchファイルを用意します。

Gmapping向けにX2LでSLAMできるようにLidar, gmapping, tfの各ノードの設定をしたlaunchファイルが以下の内容です。

ファイル名は slam_gmapping.launchとします

<launch>
  <!-- X2L -->
  <node name="ydlidar_node"  pkg="ydlidar_ros"  type="ydlidar_node" output="screen" respawn="false" >
    <param name="port"         type="string" value="/dev/ydlidar"/>
    <param name="baudrate"         type="int" value="115200"/>
    <param name="frame_id"     type="string" value="base_link"/>
    <param name="resolution_fixed"    type="bool"   value="true"/>
    <param name="auto_reconnect"    type="bool"   value="true"/>
    <param name="reversion"    type="bool"   value="false"/>
    <param name="angle_min"    type="double" value="-180" />
    <param name="angle_max"    type="double" value="180" />
    <param name="range_min"    type="double" value="0.1" />
    <param name="range_max"    type="double" value="12.0" />
    <param name="ignore_array" type="string" value="" />
    <param name="frequency"    type="double" value="8"/>
    <param name="samp_rate"    type="int"    value="3"/>
    <param name="isSingleChannel"    type="bool"   value="true"/>
  </node>

  <!-- gmapping -->
  <node pkg="gmapping" type="slam_gmapping" name="mapper">
    <param name="maxUrange" value="8.0" type="double" />
    <param name="delta" value="0.03" />
    <param name="xmax" value="30" type="double" />
    <param name="ymax" value="30" type="double" />
    <param name="xmin" value="-30" type="double" />
    <param name="ymin" value="-30" type="double" />
  </node>

  <!-- tf -->
  <node pkg ="tf" type="static_transform_publisher" name="map_to_odom" args="0.0 0.0 0.0 0.0 0.0 0.0 /map /nav 40"/>
  <node pkg ="tf" type="static_transform_publisher" name="odom_to_base_link" args="0.0 0.0 0.0 0.0 0.0 0.0 /nav /base_footprint 40"/>
  <node pkg ="tf" type="static_transform_publisher" name="base_link_to_laser" args="0.2245 0.0 0.2 0.0 0.0 0.0 /base_footprint /base_link 40" />
</launch>

動かしてみる

いよいよ動かしてみます。

以下のコマンドでslam_gmapping.launchを起動します

roslaunch my_rober slam_gmapping.launch

エラーなくログに以下の1行が表示されたらセンサーは正常に起動しています。

[YDLIDAR INFO] Now YDLIDAR is scanning ......

続いてRvizでマッピングした内容を表示します。

ワークスペースディレクトリ上で以下のコマンドを実行し、設定ファイルを読み込んでRvizを起動します。

rosrun rviz rviz -d $(find $(pwd) -name gmapping.rviz)

実行すると以下のようにLidarから作成した地図が表示されるようになります。

ACアダプターに接続していて大きく移動してないので地図は更新されることはありません。

多分ロボットが自由に動かせる状態にして動き回れば更新させられるはずです…

ここでSLAMで必要になる座標情報を扱うtfで配信されているフレームのtransformツリーを確認するために以下のコマンドを実行します。

rosrun tf view_frames

実行すると 以下のようにtransformツリーのframes.pdfが出力されます。

まとめ

今回はRaspberry PiでSLAMをできるようにしてみました。

SLAMはなかなか日本語の文献がなくて、しかもYDLidar向けだとなかなか情報が見つからなくてここまでできるのに結構時間がかかりました。

この辺の知識は学生時代に授業でやってたことだとは思うのですが、真面目に授業受ければよかったなと後悔しましたw。

これでSLAMがなんとかできるようになったので次回は実際に走行させて地図を作成していきます。