双腕移動台車ロボットを用いた認識操作プログラミング

目次

2. 双腕移動台車ロボットを用いた認識操作プログラミング#

2.1. 本日の演習内容#

本日の演習では双腕移動台車アームロボット JSK Educational Dual-armed wheelY robot (Jedy・ジェディ) の全体構成について説明し ROSによる移動台車の駆動方法と画像・深度センサを用いた視覚処理について学んでいく.

ここで説明するロボットシステム構成の内容は移動台車に限る話ではなく 来年度から配属することになる研究室で用いられる多くのロボットにおいても 実装言語の違いこそあるものの共通する重要な話である. また本日演習は移動台車アームロボットの実機で行うがほとんどの内容をシミュレーションでも行えるようにしており演習資料の後半に掲載しているので,演習中に実機で動かしたシステムを後からシミュレーションで復習したり新たな発展課題をシミュレーションで挑戦することもできるようにしてある. 演習中に分からなかったところや挑戦できなかったところもシミュレションで試してみることで 来年度から使うであろう研究室のロボットのシステムへの理解に繋げてくれるとうれしい.

演習に先立ち貸出物品の確認,ソフトウェアのインストール確認とソフトウェアのアップデートの確認を行うこと.

本日の目標は以下である.

  • ROSのコマンドの使い方を覚える(ros2 topic, ros2 launch, rostopic, roslaunchなど)

  • ROSのtopicpublish/subscribeをできるようになる

  • 異なるPC間でROSの通信の設定が行えるようになる(ROS_DOMAIN_ID, ROS_AUTOMATIC_DISCOVERY_RANGE)

  • ROS 2とROS 1間でトピックのやりとりができるようになる(ros1_bridge)

  • ROSの画像認識ノードを使って認識結果に基づいてロボットを動かす

  • ROSのGUIツールの使い方を覚える

    rqt_image_view カメラ画像・深度データを表示するツール

    Rviz カメラ画像や関節角度などのセンサの計測データ・制御の指令値,座標系などの計算結果などを3次元で可視化するツール

    rqt_reconfigure ROSのノードのパラメータをGUIから動的に変更するツール

Important

各チェックポイントを達成しながら,進捗報告シートへの記入を進め,全てのチェックポイントの進捗報告を完了せよ.各チェックポイントの結果をスクリーンショット等で保存しておくこと. 発展課題に関しては必須ではないが,すべてをこなすとかなりのロボットレベルが上がるため,これからロボットをやっていきたいというロボット経験者も未経験者もぜひチャレンジしてほしい.

2.1.1. 本演習の貸出物品#

本演習では双腕移動台車ロボットなどの貸出を行う.貸出表に借りた物品を記載して演習終了時に回収する.

  1. 双腕移動台車ロボット(ロボット本体,USB-PD充電器,充電type-cケーブル.) ロボット本体には,ステレオカメラD405,サーボ制御基板,小型ディスプレイAtom S3,マイクとスピーカーのAtom Echo,Raspberry Pi,Pisugar充電基板,USBケーブルが付属している.

  2. ジョイスティックコントローラ (本体とUSB miniBケーブル.必須ではないが,ロボット操作が面白くなるので試すことを推奨する.詳細はジョイスティックコントローラによる操縦を参照.使いたい人はTAに申し出る)

2.1.2. 環境構築とソフトウェア更新#

演習を開始する前に,必ず環境構築のページを参照して,最新バージョンのソフトウェアを取得すること.

2.1.3. ROSコマンドなどのおさらい#

2.1.3.1. ROS 1コマンド#

$ rostopic list
# topic一覧がでる
$ rostopic hz /atom_s3_button_state
# 周期がわかる
$ rostopic type /atom_s3_button_state
# topicの型が何かわかる
$ rostopic echo /atom_s3_button_state
# topicの内容を表示する
$ rosnode list
# rosnode一覧
$ rosmsg show std_msgs/Int32
# topicのmsgの型の中身が分かる
$ rqt_graph
# ノード一覧がグラフとして表示される

2.1.3.2. ROS 2コマンド#

$ ros2 topic list
# topic一覧がでる
$ ros2 topic hz /atom_s3_button_state
# 周期がわかる
$ ros2 topic info /atom_s3_button_state
# topicの型とpublisher/subscriber数が分かる
$ ros2 topic echo /atom_s3_button_state
# topicの内容を表示する
$ ros2 node list
# rosnode一覧
$ ros2 interface show std_msgs/msg/Int32
# topicのmsgの型の中身が分かる
$ rqt_graph
# ノード一覧がグラフとして表示される

詳細なコマンドの使い方についてはROS 1コマンドROS 2コマンドのTipsページを参照すること.

2.2. 実機編: 双腕移動台車ロボット Jedy#

本章では実機の双腕移動台車ロボットJedyについてハードウェアとソフトウェアの概要を説明し,実際のロボット起動方法と運用方法を紹介する.

実機を使用することで以下を学ぶことができる:

  • 実際のハードウェアの構成と制約

  • 物理的なセンサ・アクチュエータとの通信

  • ネットワーク経由でのロボット制御

  • 実世界での動作確認とデバッグ

注意: 実機は台数に限りがあるため班で共有して使用する.シミュレーション環境も用意されているので,各自のPCでシミュレーションを実行しながら実機と交代で演習を進めることを推奨する.シミュレーション環境については次章「シミュレーション編」を参照すること.

2.2.1. 双腕移動台車ロボットJedy ロボットシステム概説#

本節では双腕移動台車ロボットJedyのハードウェアおよびソフトウェアシステムについて概説する.

_images/jedy.png

図 24 双腕移動台車ロボットの外観#

_images/system-configuration-all.png

図 25 双腕移動台車ロボットシステム構成 センサ・アクチュエータデバイスとソフトウェアモジュール群 緑:ROSノード,赤:アクチュエータ,青:センサ,破線:ROS topic通信,実線:デバイスへのアクセス・その他#

本演習で使用するロボットは,台車部分と双腕,顔部を組み合わせたシステムである(参照)[1].コンパクトな計算機としてRaspberry Pi(ARMアーキテクチャ)を搭載しており無線通信を介して遠隔PCからサーボ制御や画像データの送受信が可能である.複数の構成要素(アクチュエータ,センサ,計算機)を組み合わせることで柔軟で再構成可能なロボットシステムを実現している.なお実際のロボットも,異なる構成要素(アクチュエータ・センサ・計算機)を組み合わせるだけでなく,それらがひとまとまりになったロボット自体や要素部品を複数組み合わせて作る場合が多い.

2.2.1.1. 関節・脚・グリッパ・頭部の構成#

ロボットには,以下の特徴的なモジュールが含まれる:

  • 腕:7自由度の関節構成での双腕構成

  • 車輪部:4軸のメカナムホイール

  • グリッパ:1軸で物体を掴む機構

  • 頭部:RGB距離画像生成用カメラ(Intel RealSense D405[2]),マイク・スピーカ内蔵M5ATOM Echoなどのセンサ群が搭載されている

ロボット全体で22の関節を持ち,Kondo製KRSシリーズサーボを使用して各関節の駆動を行う. KRSシリーズには赤サーボ(高負荷用)と緑または青サーボ(軽負荷用)が含まれ,用途に応じて適切なサーボが選ばれている.

2.2.1.2. 電源・バックパック・胴体構成#

  • 胴体:STM32H7マイコンボードを搭載し各関節やセンサボードとの通信を行う.また,近藤科学社製サーボ用の通信プロトコル(ICS)を用い,ロボットの動作制御を実現する.

2.2.1.3. ソフトウェアシステム#

ロボットの制御にはROS(Robot Operating System)を使用しセンサ・アクチュエータデバイスを効率的に管理する. 図.25に示すように,各デバイスはROSノードとして扱われ, topic通信(破線)やデバイスへの直接アクセス(実線)によって制御が行われる.制御用のPC(遠隔PC)からの指令を受け,リアルタイムでロボットの挙動を操作できる. 赤はアクチュエータ,青がセンサ,緑がロボットが知的に振る舞うためのソフトウェアのプロセス単位である. 演習で登場するプロセス群は以降の演習で詳細にプログラムの起動方法や 各プロセスの説明を行うので その都度今回の資料と照らし合わせてみてほしい. デバイスにアクセスできるプログラムはデバイスに接続しているPCのみから行われている. デバイスには直接アクセスできないがROSを介してネットワーク越しにデバイスから得られたデータにアクセスができる.

また今回の演習ではROSのパッケージ管理および通信を 利用してロボットを動かしセンサ情報を利用していくため 必要に応じて説明を追加していく.緑プロセスは, 厳密にはROSノードの単位になっている. また,破線矢印がROSの通信であるtopic通信になっている.

2.2.2. 双腕移動台車ロボット関連の準備#

演習に先立ち,Jedyと(推奨)ジョイスティックコントローラの充電を行う. ジョイスティックコントローラは必須ではないが,ロボット操作が面白くなるので試すことを推奨する. 詳細はジョイスティックコントローラによる操縦を参照すること.

_images/how_to_charge.png

図 26 充電方法#

Jedyの計算機であるRaspberry PiUSB-PD充電器と接続したtype-Cケーブルに接続して充電する.

推奨: ジョイスティックコントローラも充電しておく. ジョイスティックコントローラを USB miniBケーブルで演習PCと接続し, LEDが赤く点滅すれば充電中である. 充電方法の詳細はジョイスティックコントローラによる操縦を参照すること.

本演習で小型PCに接続されているケーブルは,USBデバイスケーブルはステレオカメラD405Lidarセンサの2つ,サーボ制御基板と接続されているZH3線ケーブル,マイク・スピーカのAtom Echoと接続されている4線のGroveケーブルとなる.

2.2.3. チェックポイント2.3: Caps LockをCtrlに変更する#

プログラミングやロボット開発の現場では,ターミナルやエディタでCtrlキーを頻繁に使用する. 標準的なキーボード配置ではCtrlキーが左下隅にあり小指を大きく伸ばす必要があるため,長時間作業すると手首や小指に負担がかかる. そこで,Caps LockキーをCtrlキーに変更することで,ホームポジションから指を大きく動かさずにCtrlキーを使用できるようになり,作業効率が大幅に向上する.

チェックポイント 7 (Caps LockをCtrlに変更)

  1. 以下のコマンドを実行してCaps LockをCtrlに変更せよ:

    $ gsettings set org.gnome.desktop.input-sources xkb-options "['ctrl:nocaps']"
    
  2. 設定が正しく適用されているか確認せよ:

    $ gsettings get org.gnome.desktop.input-sources xkb-options
    ['ctrl:nocaps']
    
  3. Caps Lockキーを押してCtrlキーとして機能することを確認せよ.環境によっては設定が即座に反映されない場合があるため,反映されない場合は一度PCを再起動して確認すること

  4. ターミナルでCtrl+Rを押して履歴検索ができることを確認せよ.Ctrl+Rを押すと(reverse-i-search):というプロンプトが表示されるので,過去に実行したコマンドの一部を入力して検索できることを確認せよ.例えば,cdと入力すると過去に実行したcdコマンドが表示される.見つかったコマンドはEnterで実行,Escでキャンセルできる

  5. 詳細についてはCaps LockをCtrlに変更するターミナルの制御キーを参照し,ターミナルで頻繁に使用する制御キー(Ctrl+C, Ctrl+Z, Ctrl+D, Ctrl+A, Ctrl+Eなど)についても確認しておくこと

Tip

Caps LockをCtrlに変更する設定は,長年プログラマーコミュニティで受け継がれてきた知恵であり,vi,Emacs,シェルなどのUNIXツールでCtrlキーを頻繁に使用するプログラマーにとって非常に有用である.一度この設定に慣れると,元のキーボード配置には戻れなくなるほど快適である.特に,ROSのプログラミングやターミナル操作を長時間行う本演習では,この設定により作業効率が大幅に向上する.

**演習終了後に元の設定に戻したい場合は,**以下のコマンドで設定を解除できる:

$ gsettings set org.gnome.desktop.input-sources xkb-options "[]"

ただし,多くのプログラマーはこの設定を気に入って継続して使用している.一度試してみて,快適であればそのまま使い続けることを推奨する.

2.2.4. チェックポイント2.4: ソフトウェアの更新#

演習を開始する前に,最新のソフトウェアを取得し,必要なパッケージをインストールする必要がある.

チェックポイント 8 (ソフトウェアの更新)

演習を開始する前に,以下の手順で最新のソフトウェアを取得し,必要なパッケージをインストールせよ.

  1. 以下のリンクからjsk-enshu-ros-jazzy-ros1-bridgeパッケージをダウンロードせよ:

    jsk-enshu-ros-jazzy-ros1-bridge_0.10.3-0noble_amd64.deb

  2. ダウンロードしたパッケージをインストールせよ(ダウンロードフォルダで実行):

    $ cd ~/Downloads
    $ sudo dpkg -i jsk-enshu-ros-jazzy-ros1-bridge_0.10.3-0noble_amd64.deb
    
  3. ROS 2ワークスペースのソースコードを更新せよ:

    $ cd ~/ros2_ws/src/robot-programming
    $ git pull
    $ cd ~/ros2_ws
    $ colcon build --symlink-install --packages-up-to jedy_bringup
    

    最新のソースコードが取得できることを確認せよ.

  4. ROS 1ワークスペースのソースコードを更新せよ:

    $ cd ~/ros_ws/src/robot-programming
    $ git pull
    

    最新のソースコードが取得できることを確認せよ.

Tip

git pullを実行した際に「Already up to date」と表示される場合は,すでに最新のコードになっているため問題ない.更新がある場合は,どのファイルが更新されたかが表示される.

2.2.5. チェックポイント2.5: 物品の準備#

チェックポイント 9 (物品の準備)

  1. USB-PDにつないだマグネットコネクターでJedyのRasberrypiのバッテリーを充電しLEDが点灯することを確認せよ

  2. 必須ではないがロボット操作が面白くなるので試すことを推奨: ジョイスティックコントローラをUSBケーブルで自分のノートPCに接続しLEDが点滅することを確認せよ.ジョイスティックコントローラによる操縦も参照すること

2.3. 双腕移動台車ロボット Jedy の起動方法#

本章では移動台車ロボットJedyのソフトウェアについて説明する.

2.3.1. ROS通信の接続確認#

まずJedyのロボットPCjedy-wifiに接続されている. 本演習は人数が多いものとなり後半の実機操作で画像を用いるものが出てくると通信状況によってはうまくいかない可能性がある. そのためシミュレーションで行う者はUTokyo Wi-Fiに接続すること.実機を動かす場合にはjedy-wifiに自分のPCをつなぎぐこと. Ubuntuの右上の設定から0000UTokyoというSSID無線ネットワークに接続しよう. 適宜UTokyo-WiFiへの接続の設定を参照すること.

ロボットシステムの講義でrosノード間の通信の方法を学んできたと思う. ROSの通信設定を行うことで異なるPC間で起動したrosノード間でも通信を行うことできるようになる. 本演習ではJedyもROS 2のノードを起動させ,そのノードと通信することで遠隔のPCからJedyを動かしていく. 本節ではロボットPCと各自のPCとの間のROSの通信設定を行うことで異なるPC間でのROS通信に挑戦する.

本演習で使用するJedyには,あらかじめ固有のROS_DOMAIN_IDが設定されている.このIDはロボット背面のAtom S3ディスプレイに表示されている.実機のROS 2ノードと通信するには,自分のPCでも同じROS_DOMAIN_IDを設定する必要がある. Jedyの計算機(Raspberry Pi)の電源が入っている状態でJedyの背面のAtom S3にロボットPCのIPアドレスとDOMAIN_ID(ROS_DOMAIN_IDのこと)が表示されているのを確認した上で以下のコマンドを実行する.

まず,Jedyの背面のAtom S3ディスプレイでROS_DOMAIN_IDを確認する.ディスプレイには以下のような情報が表示されている:

_images/atoms3-ip-and-ros-domain-id.jpg

図 27 Atom S3ディスプレイに表示されるIPアドレスとROS_DOMAIN_ID#

上図のように,Atom S3ディスプレイにはロボットPCのIPアドレス(例:192.168.4.95)とDOMAIN_ID(例:1)が表示される.このDOMAIN_IDROS_DOMAIN_IDに対応する値である.

確認したROS_DOMAIN_IDを以下のように設定する:

$ export ROS_DOMAIN_ID=<Your Jedy's domain id>

ROS 2ではROS_DOMAIN_IDという環境変数を使用して通信の分離を行う. ROS_DOMAIN_IDについての詳細はROS/ROS 2ネットワーク設定を参照するとよい.

確認したROS_DOMAIN_IDを自分のPCで設定する.例えば,Atom S3Domain: 42と表示されている場合:

$ export ROS_DOMAIN_ID=42

設定が正しく行われたかを確認する:

$ echo $ROS_DOMAIN_ID

Atom S3に表示されているIDと同じ値が表示されれば設定完了である.

JedyとROS通信ができているかを確認するために以下のコマンドを実行する. ros2 topic listコマンドにより下記のようなトピックが見つかれば正しくネットワーク通信ができている.

$ source /opt/ros/jazzy/setup.bash
$ ros2 topic list
/atom_s3_additional_info
/atom_s3_button_state
/atom_s3_force_mode
/atom_s3_mode
/atom_s3_selected_modes
/pairing_information
/parameter_events
/rosout
# このようにROSのトピックが一覧できる

この状態で下記コマンドを実行してAtom S3のディスプレイをクリックしてみるとクリック数に応じて出力される数字が変わることを確認してみよう.

$ source /opt/ros/jazzy/setup.bash
$ ros2 topic echo /atom_s3_button_state
---
data: 3
---
data: 0
---
data: 0
---
data: 1
---

2.3.2. チェックポイント2.6: 実機との通信設定#

チェックポイント 10 (実機との通信設定)

  1. Jedyの背面のAtom S3ディスプレイでROS_DOMAIN_IDを確認せよ

  2. 確認したROS_DOMAIN_IDを自分のPCで設定せよ(export ROS_DOMAIN_ID=<確認したID>

  3. echo $ROS_DOMAIN_IDで設定が正しく反映されていることを確認せよ

  4. ros2 topic listコマンドで実機のROS 2トピックが表示されることを確認せよ

これで実機編の基本的な起動と接続確認が完了した.次章のシミュレーション編,またはこの後の共通操作編(「ロボットの遠隔操縦」セクション)に進もう.

2.3.3. CUIからのROSのnode確認・topicのsubscribe・publish#

ここでは CUI (Command line User Interface)により ロボットのデバイスにアクセスを行う方法を紹介する.

本セクションではROS 2のコマンドを使用した確認方法を説明する. シミュレーション環境または実機でROS 2プログラムを起動した後に,以下のコマンドでノードやトピックの状態を確認できる.

2.3.3.1. ROS 2でのnode・topic確認#

ROS 2では,以下のコマンドでノードとトピックの一覧を確認できる:

$ source /opt/ros/jazzy/setup.bash
$ source ~/ros2_ws/install/setup.bash
$ export ROS_DOMAIN_ID=<Your Jedy's ROS_DOMAIN_ID>  # 実機の場合のみ必要
$ ros2 node list # ノードの一覧
$ ros2 topic list # topic一覧

これにより,どれくらい何のノードが起動されているか,何のtopicが出力されているか(advertiseされているか)が確認できる.

Note

実機とシミュレーションでの違い

  • シミュレーションの場合ROS_DOMAIN_IDの設定は不要(デフォルト値が使用される)

  • 実機の場合:ロボットPCのROS_DOMAIN_IDと同じ値を設定する必要がある(.bashrcに書いておくと便利)

2.3.3.2. topicのsubscribe(データ受信)#

実際にtopicsubscribeしてロボットからのデータを確認してみよう.

$ ros2 topic echo /atom_s3_button_state

Atom S3のディスプレイを手でクリックしてみてボタンの値が取得できることを確認しよう.

2.3.3.3. topicのpublish(データ送信)#

次に,topicpublishしてロボットへ指令を送る方法について紹介する.

$ ros2 topic pub --once /atom_s3_additional_info std_msgs/msg/String "data: 'hello robot programming-enshu'"

と実行すると背面のAtom S3hello robot programming-enshuという文字列が写るのが分かる.ASCII文字列で好きな文字列を送ってみよう.

上記コマンドでは:

  • /atom_s3_additional_infoの部分がトピック名

  • std_msgs/msg/Stringはトピックの型(type)

  • 最後が中身の値

トピックの型が分からない場合には,以下のコマンドでトピック名から型名を取得することができる:

$ ros2 topic info /atom_s3_additional_info
Type: std_msgs/msg/String
Publisher count: 1
Subscription count: 0

Tip

ROS 1とROS 2のコマンドの違い

ROS 1を使う場合(実機でROS 1のノードと直接通信する場合など)は,以下のようにコマンドが異なる:

操作

ROS 2

ROS 1

topicのpublish

ros2 topic pub --once

rostopic pub -1

型名の指定

std_msgs/msg/String

std_msgs/String

文字列の囲み方

シングルクォート('hello'

ダブルクォートまたは囲まない

topic情報の確認

ros2 topic info

rostopic type

2.3.3.4. topicのsubscribeとpublishを同時に確認#

また,別のターミナルでtopicsubscribeした状態でpublishすると, 送信されたデータが確認できる.

# ターミナル1: subscribe
$ ros2 topic echo /atom_s3_additional_info

# ターミナル2: publish
$ ros2 topic pub --once /atom_s3_additional_info std_msgs/msg/String "data: 'hello'"

ターミナル1で,ターミナル2から送信されたメッセージが表示されることを確認しよう.

ここで重要なのは,あくまでロボットの各種デバイスにアクセスしているROSノードはそれぞれ1つずつでありそれ以外のROSノードは通信(この場合ROSの通信)によって間接的にデバイスにアクセスするという点である. ロボットに知的な振る舞いをさせる行動プログラミングをさせる場合, デバイスと知的処理を行うプログラムを同一のものにしてしまうと ロボットに強く依存したプログラムとなってしまう. また,別なロボットでその知的処理を行うプログラムが動かなくなってしまう場合がある. 通信を介してプログラムを構成することで 比較的容易にプログラムの再利用性を維持しながら 知的処理のプログラミングを行うことができる.

次の課題に取り組んでみよう.topicの型の確認方法について 課題の前に必ず付録を参照すること.

2.3.4. チェックポイント2.7: topicを使ったセンサ値の確認#

チェックポイント 11 (topicを使ったセンサ値の確認)

  1. topic echoコマンドを使い, Jedyに何か働きかけるとその値が変わることを確認せよ. 例えば

    $ ros2 topic echo /atom_s3_button_state # ボタン
    

    などを確認してみよう.

ros2 topic listして表示されるものを手当たり次第にros2 topic echo, ros2 topic pubして確認してもよい.

これで実機編の基本的な起動と接続確認が完了した.次章のシミュレーション編,またはこの後の共通操作編に進もう.

2.4. シミュレーション編:Gazeboシミュレーション#

本章ではGazeboシミュレーション環境について説明する.シミュレーションを使用することで各自のPCで実機と同等の動作確認を行うことができる.

2.4.1. Gazeboシミュレーションとは#

Gazeboは3次元ロボットシミュレータであり,物理エンジンを用いてロボットの動作や環境との相互作用を仮想空間で再現できる.

2.4.1.1. シミュレーションの利点#

  • 並行作業:実機を待たずに各自のPCで演習を進められる

  • 安全性:実機を破損させる心配なく試行錯誤できる

  • 再現性:同じ条件で何度でも実験を繰り返せる

  • デバッグ:プログラムの動作確認が容易

2.4.1.2. 実機との違い#

シミュレーションは便利だが以下の点で実機と異なる:

  • 物理的制約の簡略化:摩擦・慣性・遅延などが理想化されている

  • センサノイズ:実機のセンサノイズが再現されていない

  • 通信遅延:ネットワーク経由の通信遅延がない

  • 予期しない問題:実機特有のハードウェアトラブルが発生しない

重要: シミュレーションで動作したプログラムが実機で必ずしも同じように動くとは限らない.最終的には実機で動作確認を行うことが重要である.

2.4.2. Gazeboシミュレーションの起動#

Important

シミュレーション実行前のネットワーク設定

Gazeboシミュレーションを実行する際は,UTokyo Wifiに接続し直すこと

実機を使用する際にはロボットPCと通信するために 1x-wifi に接続する必要があったが,シミュレーションは自分のPC上で動作するため,インターネット接続が可能な UTokyo Wifi に接続し直して実行すること.

これにより,パッケージのダウンロードやアップデートなどが必要な場合にスムーズに進められる.

2.4.2.1. jedy_gazebo.launchの起動#

Gazeboシミュレーションを起動するには以下のコマンドを実行する.

$ source /opt/ros/jazzy/setup.bash
$ source ~/ros2_ws/install/setup.bash
$ ros2 launch jedy_bringup jedy_gazebo.launch.py

起動するとGazeboのウィンドウが開き,シミュレーション環境が表示される.

注意: 初回起動時はロボットモデルのロードに時間がかかる場合がある.

2.4.2.2. Virtual Atom S3 Device#

jedy_gazebo.launch.pyを起動すると,GazeboとともにVirtual Atom S3 DeviceというGUIウィンドウが自動的に立ち上がる.これは実機のAtom S3マイコン(JedyのPCに搭載されているm5stackの小型ディスプレイ付きマイコン)を仮想的に再現したデバイスである.

_images/virtual-atom-s3.jpg

図 28 Virtual Atom S3 Deviceの初期画面./atom_s3_additional_infoトピックからのメッセージを待機している状態.#

Virtual Atom S3 Deviceは以下の2つの主要機能を持つ:

  1. 画面表示機能/atom_s3_additional_infoトピック(型:std_msgs/msg/String)をsubscribeし,受信した文字列を画面に表示する

  2. ボタン入力機能:「CLICK SCREEN」ボタンをクリックすると,/atom_s3_button_stateトピック(型:std_msgs/msg/Int32)にボタンの状態を示す整数値をpublishする

以下の動画は,jedy_gazebo.launch.pyを起動してVirtual Atom S3 Deviceに「Hello Jedy」を表示し,ボタンをクリックする様子を示している:

動画: Gazeboシミュレーションの起動とVirtual Atom S3 Deviceの操作

2.4.2.3. Virtual Atom S3への文字列送信例#

以下のコマンドでVirtual Atom S3の画面にメッセージを表示できる:

$ ros2 topic pub --once /atom_s3_additional_info std_msgs/msg/String "data: 'Hello Jedy'"

実行すると,Virtual Atom S3 Deviceの画面に「Hello Jedy」と表示される:

_images/virtual-atom-s3-hello-jedy.jpg

図 29 /atom_s3_additional_infoトピックにメッセージを送信した結果.画面に「Hello Jedy」と表示されている.#

2.4.2.4. ボタン状態の確認#

Virtual Atom S3 Deviceの「CLICK SCREEN」ボタンをクリックすると,/atom_s3_button_stateトピックに状態が配信される.以下のコマンドで確認できる:

$ ros2 topic echo /atom_s3_button_state

ボタンをクリックすると以下のような出力が得られる:

data: 0
---
data: 0
---
data: 1    # ボタンをワンクリック
---
data: 0
---
data: 5    # ボタンを押した回数分の値がpublishされる
---
data: 11   # ボタンを長押し
---
data: 12   # ボタンを長押ししたあとに離す
---
data: 0
---

dataの値はボタンの押下時間に応じて変化する.0は押されていない状態,1以上の値は押下の種類を示す.

2.4.2.5. 実機との対応#

Virtual Atom S3 Deviceは実機のAtom S3マイコンと以下の点で対応している:

  • トピック名の互換性:実機と同じトピック名(/atom_s3_additional_info, /atom_s3_button_state)を使用するため,プログラムをそのまま実機でも動作させることができる

  • 動作の再現:実機のディスプレイとボタンの動作を仮想的に再現しているため,シミュレーション環境でも実機と同じようにロボットとのインタラクションを試すことができる

これにより,実機を使わずに各自のPCでAtom S3を使ったプログラムの開発とテストが可能になる.

2.4.2.6. use_sim_timeの設定(重要)#

GazeboシミュレーションでEusLispプログラムを実行する場合,必ずuse_sim_timeパラメータを設定する必要がある.

# 1. ROS 1環境をセットアップ
$ source ~/ros_ws/devel/setup.bash

# 2. use_sim_timeパラメータを設定
$ rosparam set /use_sim_time true

# 3. EusLispプログラムを実行
$ roseus your-script.l

use_sim_timeを設定しないとTF(座標変換)のタイムスタンプエラーやセンサデータの時刻不整合が発生する.

実機に切り替える際の注意: シミュレーションから実機に切り替える場合は必ずuse_sim_timeを削除またはfalseに設定すること.設定したままだとロボットが動作しなくなる.

# use_sim_timeを削除
$ rosparam delete /use_sim_time

# または falseに設定
$ rosparam set /use_sim_time false

use_sim_timeの詳細についてはuse_sim_timeパラメータとはのTipsページを参照すること.

2.4.2.7. シミュレーション環境でのROSトピック確認#

シミュレーション起動後,別のターミナルで以下のコマンドを実行してROSトピックが正しく配信されていることを確認できる.

$ source /opt/ros/jazzy/setup.bash
$ source ~/ros2_ws/install/setup.bash
$ ros2 topic list

トピックが確認できるのと,下記のようにhead, rarm, larmという3つのactionが見つかれば正常に起動している.

$ source /opt/ros/jazzy/setup.bash
$ source ~/ros2_ws/install/setup.bash
$ ros2 action list
/head_controller/follow_joint_trajectory
/larm_controller/follow_joint_trajectory
/rarm_controller/follow_joint_trajectory

2.4.3. シミュレーション環境での演習の進め方#

シミュレーション環境では実機と同じプログラムをほぼそのまま使用できる.以下の点に注意して演習を進めよう:

  1. launchファイルの違い

    • 実機:roslaunch jedy_ros1_bridge jedy_bridge.launch

    • シミュレーション:ros2 launch jedy_bringup jedy_gazebo.launch.py

  2. use_sim_timeの設定EusLispを使う場合は必ず設定する

  3. SSHの不要:シミュレーションは自分のPCで動作するためSSH接続は不要

  4. 実機との動作の違い:シミュレーションで動作確認後,可能であれば実機でも動作確認を行うことを推奨する

2.5. 共通操作編(実機・シミュレーション両対応)#

本章以降の内容は実機とシミュレーションの両方に対応している.どちらの環境でも同じ手順で演習を進めることができる.

2.5.1. ROS 1とROS 2の混在について#

本演習ではROS 1(ROS-O)とROS 2(Jazzy)の両方を使用する.これは現実のロボット開発現場を反映した実践的な環境である.

ロボティクス分野では現在ROS 1からROS 2への移行期にあり多くの研究室や企業で両方のバージョンが共存している.メカトロボットの製作とプログラミングで扱ったメカトロボットではrosserialROS 1)とros2_controlROS 2)を組み合わせたシステムを構築しros1_bridgeを使用してこれらを統合する.

なぜROS 1ROS 2が混在しているのか,どのように統合するのか,将来の展望はどうなのかについては付録のROS 1とROS 2の混在環境を参照すること.

2.5.1.1. ROS 1とROS 2の連携#

本演習ではプログラミング言語としてEusLispを使用する場面がある.EusLispROS 1のみをサポートしているため,ROS 2環境とROS 1環境を連携させる必要がある.

ros1_bridgeのインストールと使用方法についてはROS 1 BridgeのTipsページを参照すること.

_images/follow-joint-trajectory-ros1-bridge.png

図 30 ROS 1とROS 2の連携システム構成図.ROS 1のAction Client(EusLispなど)がros1_bridgeを介してROS 2のシミュレータ(GazeboやIsaac Simなど)やros2_controlと通信する.FollowJointTrajectoryActionのGoalとFeedback/Resultがros1_bridgeで変換される.#

2.5.2. 演習への取り組み方と移動台車ロボットの共有方法#

ロボットPCと班員のPCを複数台使うことでそれぞれ個別に指令値を送ったりセンサ値を表示したりしながらロボットを動かすことができる. しかしロボットの動作自体は一人が送っている間は他の人が送ると動作が上書きされてしまうため,みんなで話ながらロボットを動かしていってほしい. **また,ロボットシステムの講義で学んだようにJedyrarm_controller, larm_controller, head_controllerという複数のコントローラーを持っているため別々のコントローラーを使って動かすことでその部位だけを動かすことができる.`**班のメンバーでそれぞれ右手だけ動かすや頭だけ動かすプログラムを同時に動かしてみることにも挑戦してみてほしい.

また,これ以降は実機とシミュレーション(Gazebo)の両方に対応している. 班員で相談して以下のいずれかの方法で取り組むとよい.

  1. 班員全員で演習に取り組みながらチェックポイントごとにロボットの動作指令を送る人を交代する.演習課題は全員で取り組む.(全員がセットアップをする必要がある.)

  2. 各々がシミュレーションで試してから,交代で実機を利用する.演習課題は個人で取り組む.(1人が実機でトラブルと全員が取り組めなくなる.)

複数台のPC接続設定はのようにこれまでも紹介しているROS_DOMAIN_IDを用いる.

2.6. ロボットの遠隔操縦#

本節ではロボットの台車を動かす指令値について説明し,様々な方法で指令値を与えロボットを操縦する方法を紹介する. 台車の操縦方法と,台車側が受け取る指令値,複数の指令インターフェースについて説明する.

注意: 実機で台車を動かす場合は必ず地面にJedyを置いてから動かすこと.

2.6.1. ロボットPCへのリモートアクセス#

ロボットPCにはキーボードやディスプレイが接続されていないためネットワーク経由でロボットPCにリモートアクセスすることでロボットPCを操作する. そのためにPingコマンドによる接続確認とSSHコマンドによるPCアクセスを行う.

2.6.1.1. Pingコマンドによる接続確認#

まずそのPCがネットワーク上で通信可能であるかを確認することが重要である. その際に使用される基本的なコマンドがpingである. pingコマンドは,指定したIPアドレスやホスト名に対してパケットを送り その応答を受け取ることで通信の可否を確認する方法である.

$ ping IPアドレス

たとえばリモートPCのIPアドレスが 192.168.1.100である場合,次のように入力する. 各自ロボットPCにpingコマンドを送ってみよう.

$ ping 192.168.1.100

pingコマンドを実行すると以下のような結果が表示される.

PING 192.168.1.100 (192.168.1.100) 56(84) bytes of data.
      64 bytes from 192.168.1.100: icmp_seq=1 ttl=64 time=0.123 ms
      64 bytes from 192.168.1.100: icmp_seq=2 ttl=64 time=0.127 ms
      ...

Pingは標準で連続して送信されるため終了させるには Ctrl + Cを押すことで停止する.

Pingで接続確認ができない場合のトラブルシューティングについてはPingで接続確認ができない場合を参照されたい.

2.6.1.2. SSHによるロボットPCへのアクセス#

本演習ではSSH(Secure Shell)を使ってロボットPCにアクセスする. 基本的な接続方法は以下の通りである.

$ ssh jedy@<ロボットPCのIPアドレス>

ロボットPCのユーザー名はjedy,パスワードもjedyである.

SSH接続の詳細(接続後の操作方法,切断方法,便利なオプションなど)についてはSSHによるロボットPCへのアクセスを参照されたい.

2.6.2. ロボットの起動方法#

本節ではロボットを起動する方法を説明する.実機を使う場合とシミュレーションを使う場合で手順が異なるため,それぞれ説明する.

2.6.2.1. 実機#

実機を動かすための手順は少し煩雑だが,以下の手順に従って設定を行う. この部分は多くの学生が詰まりやすいポイントなので,手順を丁寧に確認しながら進めること.

2.6.2.1.1. サーボバッテリーの接続と電源ON#

まず,サーボ制御基板にバッテリーを接続する必要がある. 以下の手順でバッテリーを接続し,サーボ制御基板の電源をONにする:

  1. バッテリーの接続:サーボバッテリーの白いVH2ピンコネクタをサーボ制御基板のVH2ピンに接続する

  2. 電源ON:ロボット背面にあるサーボ制御基板のスイッチを押すと,青いLEDが点灯し,数秒後にブザー音が鳴る

_images/how_to_switch_on_jedy_servo.png

図 31 サーボ制御基板の電源ON方法#

Danger

サーボバッテリーの充電に関する重要な注意事項

サーボバッテリーを充電する際は,必ず専用のACアダプタとUSBケーブルを使用すること

絶対にPCのUSBポートには接続しないこと!

PCに接続すると,PCやバッテリーが破損する可能性がある.

_images/how_to_charge_battery.png

図 32 サーボバッテリーの正しい充電方法(専用ACアダプタを使用)#

Note

実機の使用方法(充電方法の詳細,バッテリー残量の確認,トラブルシューティング,安全上の注意事項など)については実機の使用方法を参照されたい.

2.6.2.1.2. 実機起動の3つのステップ#

実機を動かすには,大きく分けて以下の3つのステップが必要である:

  1. ロボットPC側での起動(SSH経由)

  2. 自分のPC側でのROS環境設定(jedy-wifi接続)

  3. ROS 1/ROS 2ブリッジの起動

2.6.2.1.3. ステップ1: ロボットPC側での起動#

まず,ロボットPCにSSHで接続し,基本プログラムを起動する.

$ ssh jedy@<ロボットPCのIPアドレス>
$ roslaunch jedy_ros1_bridge jedy_bridge.launch

これを立ち上げたときに出てくる下記のエラーは無視してよい.これは,/mecanum_drive_controller/referenceというトピックを出すノードが現れるとなくなるエラーである.

ERROR: Wrong input topic (or topic field): /mecanum_drive_controller/reference
[relay_stamped_to_twist-8] process has died [pid 93112, exit code 1, cmd /opt/ros/one/lib/topic_tools/transform /mecanum_drive_controller/reference /ridgeback_control/cmd_vel geometry_msgs/Twist m.twist --import geometry_msgs.msg __name:=relay_stamped_to_twist __log:=/home/jedy/.ros/log/56596c99-c427-11f0-9615-88a29e2b767a/relay_stamped_to_twist-8.log].
log file: /home/jedy/.ros/log/56596c99-c427-11f0-9615-88a29e2b767a/relay_stamped_to_twist-8*.log

実機ではロボットのサーボ制御基板の電源が入っていないと以下のような表示が繰り返される:

[INFO] [1731065750.295350]: Waiting for the port to become available
      Skipping reset for non-USB serial port: /dev/ttyAML1 cannot be reset via USB reset.
      Could not find USB device information for port /dev/ttyAML1
      Opened /dev/ttyAML1 at 1000000 baud
[ERROR] [1731065750.429634]: Waiting for the port to become available:
      Timeout: No data received.

この状態でサーボ制御基板の電源を入れ少し待つと青いLEDがついてビープ音が鳴る.上記の表示がやみ,以下のように**RCB4 ROS Bridge initialization completed.**という表示が出れば接続できている.

[INFO] [1731065854.734742]: Try to publish stretch values.
[INFO] [1731065854.923045]: RCB4 ROS Bridge initialization completed.
[INFO] [1731065854.955020]: Current limit set 4.0
[INFO] [1731065854.966799]: Temperature limit set 80

.launch」という拡張子のファイルはROSのノードを起動する起動スクリプトであり,roslaunchコマンドの引数に与えることで起動できる. .launchファイルはXMLスクリプトとして記述されており,jedy_bridge.launchでは複数のlaunchファイルを入れ子で呼び出している. C言語のincludeやPythonのimportのように,他のlaunchファイルを組み込むことでプログラムの再利用性を向上させている.

このlaunchファイルの詳細については,ROS Launchを参照すること.

2.6.2.1.4. ステップ2: 自分のPC側でのROS環境設定#

次に,自分のPCでjedy-wifiに接続した状態で,別のターミナルを開いて以下のコマンドを実行する.

# ROS環境のセットアップ
$ source /opt/ros/one/setup.bash
$ source ~/ros2_ws/install/setup.bash

# ROS 1のネットワーク設定
$ rossetip
$ rossetmaster <ロボットPCのIPアドレス>

# ROS 2のドメインID設定
$ export ROS_DOMAIN_ID=<Your Jedy's ROS_DOMAIN_ID>

Tip

ROS_DOMAIN_IDの設定を簡略化する方法

演習中は毎回export ROS_DOMAIN_ID=<ID>を実行するのが煩雑なので,以下のように.bashrcに書いておくと良い:

# ~/.bashrcに追加
export ROS_DOMAIN_ID=<Your Jedy's ROS_DOMAIN_ID>

.bashrcに追加した後は,以下のコマンドで設定を反映させる:

$ source ~/.bashrc

これにより,新しいターミナルを開くたびに自動的にROS_DOMAIN_IDが設定されるようになる.

2.6.2.1.5. ステップ3: ROS 1/ROS 2ブリッジの起動#

自分のPCで,ROS 1とROS 2を橋渡しするブリッジプログラムを起動する.

$ source ~/ros2_ws/install/setup.bash
$ export ROS_DOMAIN_ID=<Your Jedy's ROS_DOMAIN_ID>  # .bashrcに書いていない場合
$ ros2 launch jedy_bringup ros1_bridge.launch.py

このブリッジが正常に起動すると,ROS 2のプログラムからROS 1のロボット制御システムと通信できるようになる.

2.6.2.1.6. 接続確認: テレオペレーションで動作確認#

接続が正しく設定できているか,キーボードテレオペレーションやジョイスティックテレオペレーションで確認してみよう. 別のターミナルを開いて以下のいずれかを実行する:

キーボードテレオペレーションの場合:

$ source ~/ros2_ws/install/setup.bash
$ export ROS_DOMAIN_ID=<Your Jedy's ROS_DOMAIN_ID>  # .bashrcに書いていない場合
$ ros2 launch jedy_bringup keyboard_teleop.launch.py

ジョイスティックテレオペレーションの場合:

$ source ~/ros2_ws/install/setup.bash
$ export ROS_DOMAIN_ID=<Your Jedy's ROS_DOMAIN_ID>  # .bashrcに書いていない場合
$ ros2 launch jedy_bringup joystick_teleop.launch.py

うまく接続ができていると,キーボード操作やジョイスティック操作でJedyが動くはずである. ロボットが動かない場合は,上記の手順を再度確認すること.

Warning

EusLispを使用する場合の追加設定

EusLispプログラムを実機と接続して使用する場合は,EusLispを起動する前に必ず以下のコマンドを実行すること:

$ source /opt/ros/one/setup.bash
$ rossetip
$ rossetmaster <ロボットPCのIPアドレス>

これらの設定を忘れると,EusLispからロボットにアクセスできない. EusLispを使う演習では,この設定を毎回確認すること.

2.6.2.1.7. 実機での動作確認: ROS 1でのnode・topic確認#

実機のプログラムが正常に起動しているか,ROS 1のコマンドで確認してみよう. jedy_bridge.launchを起動した後,自分のPCで以下のコマンドを実行する:

$ source /opt/ros/one/setup.bash
$ rossetip
$ rossetmaster <ロボットPCのIPアドレス>
$ rosnode list # ノードの一覧
$ rostopic list # topic一覧

これにより,どれくらい何のノードが起動されているか,何のtopicが出力されているか(advertiseされているか)が確認できる.

Note

rossetiprossetmasterコマンドが見つからない場合

もしrossetiprossetmasterコマンドが存在しないというエラーが出た場合は,以下のコマンドで必要なパッケージをインストールしてから再度試してみること:

$ sudo apt install ros-one-jsk-topic-tools
$ source /opt/ros/one/setup.bash

インストール後,再度rossetiprossetmasterコマンドを実行する.

2.6.2.2. シミュレーション#

シミュレーションを使用する場合は,SSHやネットワーク設定が不要なため実機よりもシンプルに起動できる. ただし,EusLispから操作する場合は3つのターミナルを使用する必要がある点に注意すること.

2.6.2.2.1. EusLispを使わない場合(ROS 2のみ)#

ROS 2のプログラムのみを使用する場合は,1つのターミナルでGazeboシミュレーションを起動するだけでよい.

$ source /opt/ros/jazzy/setup.bash
$ source ~/ros2_ws/install/setup.bash
$ ros2 launch jedy_bringup jedy_gazebo.launch.py
2.6.2.2.2. EusLispを使う場合(ROS 1とROS 2のブリッジが必要)#

EusLispから操作する場合は,ROS 1とROS 2のブリッジを経由する必要があるため,3つのターミナルを使用する:

ターミナル1: ROS 1側でroscoreの起動

$ source /opt/ros/one/setup.bash
$ roscore

ターミナル2: ROS 2側でGazeboシミュレーションの起動

$ source /opt/ros/jazzy/setup.bash
$ source ~/ros2_ws/install/setup.bash
$ export ROS_AUTOMATIC_DISCOVERY_RANGE=LOCALHOST
$ ros2 launch jedy_bringup jedy_gazebo.launch.py

Note

ROS_AUTOMATIC_DISCOVERY_RANGE=LOCALHOSTを設定することで,ROS 2のDDS検出範囲をローカルホストに制限し,ネットワーク上の他のROS 2ノードとの干渉を防ぐ.

ターミナル3: ROS 1とROS 2のブリッジ

$ source /opt/ros/one/setup.bash
$ rosparam set /use_sim_time true
$ source /opt/ros/jazzy/setup.bash
$ source ~/ros2_ws/install/setup.bash
$ export ROS_AUTOMATIC_DISCOVERY_RANGE=LOCALHOST
$ ros2 run ros1_bridge dynamic_bridge --bridge-all-topics

Tip

シミュレーション中にロボットが倒れてしまった場合は,Gazebo Simulation の「ロボットが倒れた場合の復帰方法」を参照すること.

Note

実機との違い

シミュレーションでは以下の点が実機と異なる:

  • SSHでロボットPCに接続する必要がない

  • ROS_DOMAIN_IDの設定が不要(デフォルト値が使用される)

  • すべてのプログラムを自分のPC上で実行できる

2.6.2.3. 実機・シミュレーション両方#

以降の演習では,実機とシミュレーションのどちらでも同様のコマンドでロボットを操作できる. ただし,実機の場合は適切なネットワーク設定(ROS_DOMAIN_IDなど)が必要である点に注意すること.

2.6.3. Python / EusLispからの利用#

講義ではPythonEusLispからtopicsubscribe, publishする方法を紹介した. これらのプログラミング言語からJedytopicsubscribe, publishする次の課題に取り組んでみよう. 詳細なコードはROS wikiのサンプルページ [4]が参考になる. 課題の前に必ず付録を参照すること.

2.6.4. チェックポイント2.8: PythonまたはEusLispからのtopic操作#

チェックポイント 12 (PythonまたはEusLispからのtopic操作)

  1. ボタンのセンサ値のtopicsubscribeし表示するPythonもしくはEusLispのプログラムを作成せよ

  2. stringpublishしディスプレイに文字を表示するPythonもしくはEusLispのプログラムを作成せよ

  3. IMUの値を/imuトピックから取得しロボットを傾けるとどのくらい傾いているかをrollpitch角度を計算して出力するPythonもしくはEusLispのプログラムを作成せよ

それぞれ,TAに確認を受けること.

難しければ

$ cd ~/ros_ws/src/robot-programming/jedy/jedy_bringup/exercise/
# または
$ cd ~/ros2_ws/src/robot-programming/jedy/jedy_bringup/exercise/
$ ls
  checkpoint1-button.l  checkpoint1-display.l  checkpoint1-imu.l
  checkpoint1_button_ros1.py  checkpoint1_display_ros1.py  checkpoint1_imu_ros1.py
  checkpoint1_button_ros2.py  checkpoint1_display_ros2.py  checkpoint1_imu_ros2.py

に,ボタンのセンサ値のtopicsubscribeし表示するプログラムや, ディスプレイに文字を表示させるプログラムがあるので参考にしてよい.

なお,EusLispの起動は通常のターミナルで直接実行するよりも,emacsM-x shellとタイプし起動したターミナルで行うことをお勧めする. 一度打ち込んだコマンドは,M-pで履歴を遡ることができるので,同じコマンド打つ手間が減る. emacsを起動するときにshellをコマンドラインから立ち上げる便利コマンドは以下のようにできる. EusLisp (roseus)のより効率的な作業方法を知りたい場合はroseusでの効率的な作業方法が参考になる.

$ emacs -nw -f shell

また,pythonプログラムを立ち上げるときは

$ python3 checkpoint1_display_ros2.py
# またはインタラクティブモードで
$ python3 -i checkpoint1_display_ros2.py

などとするとプログラムが終了時にインタラクティブシェルに入ることができるので便利である.ipython3をインストールしている人は同様に以下のようにしてできる.

$ ipython3 -i checkpoint1_display_ros2.py

注意: ROS 1を使用する場合はcheckpoint1_display_ros1.pyを,ROS 2を使用する場合はcheckpoint1_display_ros2.pyを使用すること.

2.6.5. topicのデータ内容の確認について#

ROSのコマンドを使うとデータ内容の確認や型のチェックが行える. 例えば/imutopicのデータ型を知りたいとする.

2.6.6. ROS 1でのtopic型の確認#

$ rostopic type /imu
  sensor_msgs/Imu

とするとsensor_msgsというmsg定義用のROSパッケージのImuという型であることが調べられる.

2.6.7. ROS 2でのtopic型の確認#

ROS 2では以下のコマンドを使用する:

$ ros2 topic info /imu
Type: sensor_msgs/msg/Imu
Publisher count: 1
Subscription count: 0

ROS 2では型名にmsgが含まれる(sensor_msgs/msg/Imu)点に注意すること.

2.6.8. ROS 1でのmsgデータ型の構成確認#

msgのデータ型の構成を知りたければ以下を実行する:

$ rosmsg show sensor_msgs/Imu
std_msgs/Header header
  uint32 seq
  time stamp
  string frame_id
geometry_msgs/Quaternion orientation
  float64 x
  float64 y
  float64 z
  float64 w
  float64[9] orientation_covariance
geometry_msgs/Vector3 angular_velocity
  float64 x
  float64 y
  float64 z
  float64[9] angular_velocity_covariance
geometry_msgs/Vector3 linear_acceleration
  float64 x
  float64 y
  float64 z
  float64[9] linear_acceleration_covariance

2.6.9. ROS 2でのinterfaceデータ型の構成確認#

ROS 2ではros2 interface showコマンドを使用する:

# This is a message to hold data from an IMU (Inertial Measurement Unit)
#
# Accelerations should be in m/s^2 (not in g's), and rotational velocity should be in rad/sec
#
# If the covariance of the measurement is known, it should be filled in (if all you know is the
# variance of each measurement, e.g. from the datasheet, just put those along the diagonal)
# A covariance matrix of all zeros will be interpreted as "covariance unknown", and to use the
# data a covariance will have to be assumed or gotten from some other source
#
# If you have no estimate for one of the data elements (e.g. your IMU doesn't produce an
# orientation estimate), please set element 0 of the associated covariance matrix to -1
# If you are interpreting this message, please check for a value of -1 in the first element of each
# covariance matrix, and disregard the associated estimate.

std_msgs/Header header
        builtin_interfaces/Time stamp
                int32 sec
                uint32 nanosec
        string frame_id

geometry_msgs/Quaternion orientation
        float64 x 0
        float64 y 0
        float64 z 0
        float64 w 1
float64[9] orientation_covariance # Row major about x, y, z axes

geometry_msgs/Vector3 angular_velocity
        float64 x
        float64 y
        float64 z
float64[9] angular_velocity_covariance # Row major about x, y, z axes

geometry_msgs/Vector3 linear_acceleration
        float64 x
        float64 y
        float64 z
float64[9] linear_acceleration_covariance # Row major x, y z

ROS 1とROS 2の主な違い:

  • ROS 1: rosmsg show sensor_msgs/Imu

  • ROS 2: ros2 interface show sensor_msgs/msg/Imumsg/が必要)

  • ROS 1: uint32 seqフィールドがheaderに含まれる

  • ROS 2: builtin_interfaces/Time型が使用され,secnanosecに分かれる

これはImuの値となるのでJedyを持ち上げたりしてみて姿勢を変えてみると値が変わることが確認できる.

2.6.10. EusLispからのmsg利用(ROS 1のみ)#

EusLispからこれらのmsgを利用する場合,下記のようにroseus-add-msgsをプログラム冒頭で行う. また,msgのクラスにはsensor_msgs/Imuのようにrostopic typeで表示されたものの/::にかえたものでアクセスできる.

注意: EusLispROS 1のみをサポートしているため,ROS 2環境ではros1_bridgeを使用してROS 1トピックに変換する必要がある.

irteusgl$ (ros::roseus-add-msgs "sensor_msgs") ;; 引数は所望のmsgのあるROSパッケージ名
irteusgl$ (print sensor_msgs::Imu)
#<metaclass #X563a77b846b0 sensor_msgs::imu>  ;; X563a77b846b0はアドレス値なので結果が異なる

2.6.11. rqtによる操縦#

$ source ~/ros2_ws/install/setup.bash
$ cd ~/ros2_ws/src/robot-programming/jedy/jedy_bringup/
$ rqt --perspective-file enshu.perspective

とするとrqtを利用した操縦GUIが起動する. rqtから台車の速度指令を送り実機が動くことを確認しよう. ロボットが机から落ちたりしないようにを床において試すこと! 図.33rqtのウィンドウを示す.ウィンドウ左部のRobot Steeringにて台車の速度指令を送る. 上下のバーと左右のバーでそれぞれ前後方向と回転方向の指令を送る.

_images/rqt_window.jpg

図 33 rqtのウィンドウ.**Stampedにチェックをするのを忘れないように.**これはtimestampが付与されている速度指令が送られる.#

別のターミナルで

$ ros2 topic echo /mecanum_drive_controller/reference
header:
  stamp:
    sec: 1762346478
    nanosec: 11757239
  frame_id: ''
twist:
  linear:
    x: 0.0
    y: 0.0
    z: 0.0
  angular:
    x: 0.0
    y: 0.0
    z: -0.166

を見ると指令速度がtopicとして送られていることが確認できる.上記は例えば回転して方向を変えようとしている場合でangularzの値が変わっている.

2.6.12. キーボードによる操縦#

teleop_twist_keyboardパッケージを使ってロボットの台車を動かしてみよう. ロボットPCでjedy_bridge.launch(シミュレーションではjedy_gazebo.launch.py)を起動した状態で別のターミナルで

$ ros2 run teleop_twist_keyboard teleop_twist_keyboard --ros-args --remap cmd_vel:=/mecanum_drive_controller/reference  -p stamped:=true

もしくは,

$ ros2 launch jedy_bringup keyboard_teleop.launch.py

を起動する. キーボードをタイプするように表示がでてくるので 表示従いキーを押すことでロボットを 動かすことができる. iで前進,jで左旋回といったように,kを中心に 十字キーのように扱える. 速度が速い場合は,zを押して速度を遅くすることができる.

_images/keyboard-teleop.jpg

図 34 キーボードから速度指令を送っている様子#

本プログラムでも,別のターミナルで

$ ros2 topic echo /mecanum_drive_controller/reference

を見ると指令速度がtopicとして送られていることが確認できる.

2.6.13. チェックポイント2.9: ロボットの遠隔操縦#

チェックポイント 13 (ロボットの遠隔操縦)

  1. keyboard_teleoprqtの両方でロボットを操縦している様子を見せよ.

必須ではないが面白いので試してみよう:

  1. ジョイスティックコントローラによる操縦の手順でジョイスティックコントローラから操縦している様子を見せよ.ジョイスティックでロボットを操作すると,キーボードとは違った直感的な操作感を体験できる.

  2. EusLispのジョイスティックサンプル(joy-sample.l)を実行しジョイスティックの値が読めていることを確認してみよう.詳細はジョイスティックコントローラによる操縦を参照すること.

2.7. 画像・深度センサの利用(シミュレーションも対応)#

Jedyに搭載されているIntel社のD405ステレオカメラは,左右に配置された二つのカメラで同時に撮影された画像を利用し三角測量の原理を用いて深度(距離)データを計測するセンサである.三角測量では視差と呼ばれる左右のカメラ間での対象物の位置のズレを基に距離を推定する.対象物がカメラに近づくと視差は大きくなり遠ざかると小さくなるためこの視差の変化を解析して距離を算出する.

D405はこの三角測量により特に近距離での測定に優れた性能を有している点が特徴である. 一般的なステレオカメラはある程度の距離が必要となるがカメラ間の距離が短いため D405は数十センチ以下の非常に短い距離でも精度の高い距離データを取得できるよう設計されている. このため狭い空間や近接環境での距離計測においても安定したデータが得られ,物体把持やロボットの近接制御など,微細な位置調整が必要なタスクにおいて効果的に使用される.

Note

ロボットの座標系とカメラの座標系は異なる定義を持つため,カメラで認識した情報をロボット制御に使用する際は座標変換が必要である.詳細はロボットの座標系とカメラの座標系を参照すること.また,D405の詳細なセットアップ方法や技術的な特徴についてはIntel RealSense D405のセットアップと活用を参照すること.

2.7.1. 画像・深度データ取得プログラムの起動#

実際にカメラ画像を取得する方法を説明する.実機とシミュレーションで手順が異なる.

2.7.1.1. 実機#

実機では,ロボットPCでカメラノードを起動する必要がある.

ターミナル1: ロボットPCでjedy_bridge.launchを起動(既に起動している場合は不要)

$ ssh jedy@<ロボットPCのIPアドレス>
$ roslaunch jedy_ros1_bridge jedy_bridge.launch

ターミナル2: ロボットPCでd405カメラを起動

$ ssh jedy@<ロボットPCのIPアドレス>
$ source ~/ros2_ws/install/setup.bash
$ ros2 launch jedy_bringup rs_launch.py

Important

USBの接続確認

カメラノードを起動する前に,D405のUSBがJedyのUSBポートに接続されているかを確認すること.

2.7.1.2. シミュレーション#

シミュレーションでは,カメラはGazeboシミュレーションに含まれているため,追加のカメラノード起動は不要である.

2.7.1.2.1. EusLispを使わない場合(ROS 2のみ)#
$ source /opt/ros/jazzy/setup.bash
$ source ~/ros2_ws/install/setup.bash
$ ros2 launch jedy_bringup jedy_gazebo.launch.py
2.7.1.2.2. EusLispを使う場合#

EusLispから操作する場合は,ロボットの起動方法のシミュレーションセクションで説明した3つのターミナルでシミュレーションを起動する必要がある.

ターミナル1: ROS 1側でroscoreの起動

$ source /opt/ros/one/setup.bash
$ roscore

ターミナル2: ROS 2側でGazeboシミュレーションの起動

$ source /opt/ros/jazzy/setup.bash
$ source ~/ros2_ws/install/setup.bash
$ export ROS_AUTOMATIC_DISCOVERY_RANGE=LOCALHOST
$ ros2 launch jedy_bringup jedy_gazebo.launch.py

ターミナル3: ROS 1とROS 2のブリッジ

$ source /opt/ros/one/setup.bash
$ rosparam set /use_sim_time true
$ source /opt/ros/jazzy/setup.bash
$ source ~/ros2_ws/install/setup.bash
$ export ROS_AUTOMATIC_DISCOVERY_RANGE=LOCALHOST
$ ros2 run ros1_bridge dynamic_bridge --bridge-all-topics

Note

シミュレーションではd405のlaunchjedy_gazebo.launch.pyに含まれているため,別途カメラノードを起動する必要はない.

2.7.1.3. 実機・シミュレーション両方#

どちらの環境でも,ros2 topic listをすると/camera以下にtopicが大量にできているのが分かる.

$ ros2 topic list | grep camera
/camera/aligned_depth_to_color/camera_info
/camera/aligned_depth_to_color/image_raw
/camera/aligned_depth_to_color/image_raw/compressed
/camera/aligned_depth_to_color/image_raw/compressedDepth
/camera/color/camera_info
/camera/color/image_rect_raw
/camera/color/image_rect_raw/compressed
/camera/color/image_rect_raw/compressedDepth
/camera/color/metadata
/camera/depth/camera_info
/camera/depth/image_rect_raw
/camera/depth/image_rect_raw/compressed
/camera/depth/image_rect_raw/compressedDepth
/camera/depth/metadata
/camera/extrinsics/depth_to_color

以下が主に使用するTopicである.

/camera/color/image_rect_raw
/camera/aligned_depth_to_color/image_raw

このうち,rgbは画像データでありdepthは深度情報のデータである. alignedとついているのはデプス画像は一般的には別センサで実装されることが多く,RGBのカメラ画像と位置を合わせたという意味でalignedという名前がついている.

次に,remote_camera.launch.pyを立ち上げる.実機とシミュレーションで起動方法が異なるため注意すること.

実機の場合:

$ source /opt/ros/jazzy/setup.bash
$ source ~/ros2_ws/install/setup.bash
$ export ROS_DOMAIN_ID=<Your Jedy's ROS_DOMAIN_ID>
$ ros2 launch jedy_bringup remote_camera.launch.py

シミュレーションの場合:

$ source /opt/ros/jazzy/setup.bash
$ source ~/ros2_ws/install/setup.bash
$ ros2 launch jedy_bringup remote_camera.launch.py use_sim_time:=true

もう一度ros2 topic listをすると以下のようなトピックが増えている.

/remote/aligned_depth_to_color/camera_info
/remote/aligned_depth_to_color/image_raw
/remote/color/camera_info
/remote/color/image_rect_raw
/remote/depth/color/points

これは/camera/color/image_rect_raw/compressed画像をリモートPCでsubscribeし再度/remote/color/image_rect_rawとしてpublishしている. depth/color/pointsは深度・画像データをRegisteration(align位置合わせ)した結果であり主に色付き点群が含まれる. 画像データに関しては,colorはRGB画像,monoはモノクロ画像,rectがつくものはRectify処理を施したものである.

画像データを確認するためには,rqt_image_viewが便利である.自分のノートPCで

$ source /opt/ros/jazzy/setup.bash
$ source ~/ros2_ws/install/setup.bash
$ ros2 run rqt_image_view rqt_image_view

左上のトピックを選択して画像を表示する.実機とシミュレーションで選択するトピックが異なる

  • 実機の場合: /camera/color/image_rect_raw/compressed を選択

  • シミュレーションの場合: /camera/color/image_rect_raw を選択

Note

実機ではcompressed(圧縮)画像を使用する.これはネットワーク越しにロボットを動かす場合に通信の帯域を節約するために必須である.シミュレーションではローカルで動作するため圧縮していない画像を使用できる.

_images/sample_rqt_image_view.jpg

図 35 rqt_image_viewで画像を表示している例.画像は今回諸君が使用しているJedyを研究室の学生(2024年度)が組み立てている様子である.#

2.7.2. Rviz上での表示#

RvizはROS標準の3Dビューアソフトである. デフォルト設定状態のRVizは,単にrviz2と入力するだけで起動できるがjedy_gazebo.launch.pyの内部では設定済みの.rvizファイルを読み込んで起動するようにしている.

2.7.2.1. 実機#

実機でカメラ画像や点群を確認する場合は,以下の手順でRVizを起動する:

# RVizを起動
$ source /opt/ros/jazzy/setup.bash
$ source ~/ros2_ws/install/setup.bash
$ export ROS_DOMAIN_ID=<Your Jedy's ROS_DOMAIN_ID>
$ rviz2

RVizが起動したら,以下の手順で画像や点群を表示する:

  1. Fixed Frameの設定:左上の「Fixed Frame」をbase_linkまたはcamera_color_optical_frameに設定する

  2. 画像の追加:左下の「Add」ボタンをクリック → 「By display type」タブで「Image」を選択 → 「OK」

  3. トピックの選択:追加した「Image」の設定で「Topic」を/remote/color/image_rect_rawに設定する

  4. 点群の追加(オプション):「Add」→「PointCloud2」を選択 → トピックを/remote/depth/color/pointsに設定する

Note

compressed画像の再publish

実機では,カメラから送られてくる画像がcompressed(圧縮)形式のため,remote_camera.launch.pyで再publishする必要がある. 以下のコマンドを別のターミナルで実行すること:

$ source /opt/ros/jazzy/setup.bash
$ source ~/ros2_ws/install/setup.bash
$ export ROS_DOMAIN_ID=<Your Jedy's ROS_DOMAIN_ID>
$ ros2 launch jedy_bringup remote_camera.launch.py

2.7.2.2. シミュレーション#

シミュレーションでは,jedy_gazebo.launch.pyを起動すると自動的にRVizも起動されるため,明示的に起動する必要はない.

Note

シミュレーションでは設定済みの.rvizファイルが自動的に読み込まれるため,カメラ画像や点群が既に表示されている場合がある.

2.7.2.3. Rviz上でのtopicの追加#

RvizではGUIインターフェースにより表示するデータを追加や削除をすることができる. そのためには,表示したいtopicの (1)型の選択,及び(2)名前の選択を行う. 図.36の約左半分はDisplays欄と呼ばれるものでありその中に topicの型が並びそれぞれチェックボックスがついている. 例えばImageの行のチェックボックスにチェックをいれ, 左の三角をクリックしてプルダウンメニューを開くと さらに色々と項目がでてくる. そのうち,topicとかいてある欄もプルダウンメニューになっており プルダウンメニューには今advertiseされているtopic名の一覧が表示される (図.36の3). 例えば/remote/color/image_rect_rawを選ぶと画像が表示される.

Display欄の下側にAdd, Remove, Renameというボタンがついており (図.36の1), Addで新たに型・topicを追加することができる. Addボタンを押すとウィンドウがたちあがり ここから型・topic名を選択して新たに表示したいものを追加できる (図.36の2). 例えばAddボタンで起動するウィンドウからPointCloud2を選択すると Display欄の下の方に,PointCloud2が追加される. 後は先ほど同様の手順で表示するtopicを選択する. この例の場合,“Topic”欄のプルダウンから/remote/depth/color/points を選択すると3次元点群が表示される.

_images/add_rviz_topic.jpg

図 36 Rvizのtopic追加方法#

2.8. 三次元物体認識#

本章ではアームで物体を把持する際などに必要となる物体の三次元位置認識について二種類の方法を説明する[5].

2.8.1. checkerboard_detectorによる3次元姿勢認識#

ここでは2次元画像から3次元位置姿勢推定を行う例について紹介する. 一般には2次元画像から3次元位置姿勢を行うことは困難であるが対象側のマーカ情報やパターン情報が 既知であればそれを利用して3次元情報を復元することができる.

2.8.2. プログラムの起動#

checkerboard認識を実行する方法を説明する.実機とシミュレーションで手順が異なる.

2.8.2.1. 実機#

実機では,以下のプログラムをそれぞれ別のターミナルで起動する:

ターミナル1: ロボットPCでjedy_bridge.launchを起動(既に起動している場合は不要)

$ ssh jedy@<ロボットPCのIPアドレス>
$ roslaunch jedy_ros1_bridge jedy_bridge.launch

ターミナル2: ロボットPCでd405カメラを起動(既に起動している場合は不要)

$ ssh jedy@<ロボットPCのIPアドレス>
$ source ~/ros2_ws/install/setup.bash
$ ros2 launch jedy_bringup rs_launch.py

ターミナル3: 自分のPCでroscoreを起動

$ source /opt/ros/one/setup.bash
$ roscore

ターミナル4: 自分のPCでROS 1/ROS 2ブリッジを起動

# ROS環境のセットアップ
$ source /opt/ros/one/setup.bash
$ source ~/ros2_ws/install/setup.bash

# ROS 1のネットワーク設定
$ rossetip
$ rossetmaster <ロボットPCのIPアドレス>

# ROS 2のドメインID設定
$ export ROS_DOMAIN_ID=<Your Jedy's ROS_DOMAIN_ID>

# ros1_bridgeを起動
$ ros2 launch jedy_bringup ros1_bridge.launch.py

ターミナル5: 自分のPCでremote_camera.launch.pyを起動

$ source /opt/ros/jazzy/setup.bash
$ source ~/ros2_ws/install/setup.bash
$ export ROS_DOMAIN_ID=<Your Jedy's ROS_DOMAIN_ID>
$ ros2 launch jedy_bringup remote_camera.launch.py

ターミナル6: 自分のPCでcheckerboard_detector.launch.pyを起動

$ source /opt/ros/jazzy/setup.bash
$ source ~/ros2_ws/install/setup.bash
$ export ROS_DOMAIN_ID=<Your Jedy's ROS_DOMAIN_ID>
$ ros2 launch jedy_bringup checkerboard_detector.launch.py

2.8.2.2. シミュレーション#

シミュレーションでは,ROS 2のみを使う場合とEusLispを使う場合で手順が異なる.

2.8.2.2.1. EusLispを使わない場合(ROS 2のみ)#

以下の2つのターミナルで起動する:

ターミナル1: Gazeboシミュレータを起動(既に起動している場合は不要)

$ source /opt/ros/jazzy/setup.bash
$ source ~/ros2_ws/install/setup.bash
$ ros2 launch jedy_bringup jedy_gazebo.launch.py

ターミナル2: checkerboard_detector.launch.pyを起動

$ source /opt/ros/jazzy/setup.bash
$ source ~/ros2_ws/install/setup.bash
$ ros2 launch jedy_bringup checkerboard_detector.launch.py input_topic:=/camera/color/image_rect_raw camera_info_topic:=/camera/color/camera_info use_sim_time:=true
2.8.2.2.2. EusLispを使う場合#

EusLispから認識結果を利用する場合は,以下の4つのターミナルで起動する:

ターミナル1: ROS 1側でroscoreの起動

$ source /opt/ros/one/setup.bash
$ roscore

ターミナル2: ROS 2側でGazeboシミュレーションの起動(既に起動している場合は不要)

$ source /opt/ros/jazzy/setup.bash
$ source ~/ros2_ws/install/setup.bash
$ export ROS_AUTOMATIC_DISCOVERY_RANGE=LOCALHOST
$ ros2 launch jedy_bringup jedy_gazebo.launch.py

ターミナル3: ROS 1とROS 2のブリッジ

$ source /opt/ros/one/setup.bash
$ rosparam set /use_sim_time true
$ source /opt/ros/jazzy/setup.bash
$ source ~/ros2_ws/install/setup.bash
$ export ROS_AUTOMATIC_DISCOVERY_RANGE=LOCALHOST
$ ros2 run ros1_bridge dynamic_bridge --bridge-all-topics

ターミナル4: checkerboard_detector.launch.pyを起動

$ source /opt/ros/jazzy/setup.bash
$ source ~/ros2_ws/install/setup.bash
$ ros2 launch jedy_bringup checkerboard_detector.launch.py input_topic:=/camera/color/image_rect_raw camera_info_topic:=/camera/color/camera_info use_sim_time:=true

2.8.2.3. 実機・シミュレーション両方#

上記の手順でcheckerboard認識プログラムを起動すると,CheckerboardDetectorとかかれたビューワが表示される. 紙に印刷されたCheckerboardパターン [6] をカメラ前に持っていくと,格子の認識結果が表示される. カメラ視界内にチェッカーボードが入ると,格子の認識結果が表示される.

上記launch.pyの中では

from launch import LaunchDescription
from launch.actions import DeclareLaunchArgument
from launch.substitutions import LaunchConfiguration
from launch_ros.actions import Node


def generate_launch_description():
    # Launch arguments
    use_sim_time_arg = DeclareLaunchArgument(
        'use_sim_time',
        default_value='false',
        description='Use simulation time'
    )

    input_topic_arg = DeclareLaunchArgument(
        'input_topic',
        default_value='/remote/color/image_rect_raw',
        description='Input image topic'
    )

    camera_info_topic_arg = DeclareLaunchArgument(
        'camera_info_topic',
        default_value='/remote/color/camera_info',
        description='Camera info topic'
    )

    checkerboard_size_arg = DeclareLaunchArgument(
        'checkerboard_size',
        default_value='[6, 4]',
        description='Checkerboard size (internal corners): [width, height]'
    )

    square_size_arg = DeclareLaunchArgument(
        'square_size',
        default_value='0.02',
        description='Size of one checkerboard square in meters'
    )

    checkerboard_frame_arg = DeclareLaunchArgument(
        'checkerboard_frame',
        default_value='checkerboard',
        description='Checkerboard frame ID'
    )

    # Node
    checkerboard_detector_node = Node(
        package='jedy_bringup',
        executable='checkerboard_detector.py',
        name='checkerboard_detector',
        output='screen',
        parameters=[
            {'use_sim_time': LaunchConfiguration('use_sim_time')},
            {'input_topic': LaunchConfiguration('input_topic')},
            {'camera_info_topic': LaunchConfiguration('camera_info_topic')},
            {'checkerboard_size': LaunchConfiguration('checkerboard_size')},
            {'square_size': LaunchConfiguration('square_size')},
            {'checkerboard_frame': LaunchConfiguration('checkerboard_frame')},
        ]
    )

    # Image view node
    image_view_node = Node(
        package='image_view',
        executable='image_view',
        name='checkerboard_image_view',
        output='screen',
        parameters=[
            {'use_sim_time': LaunchConfiguration('use_sim_time')},
        ],
        remappings=[
            ('image', '/checkerboard_detector/debug_image')
        ]
    )

    return LaunchDescription([
        use_sim_time_arg,
        input_topic_arg,
        camera_info_topic_arg,
        checkerboard_size_arg,
        square_size_arg,
        checkerboard_frame_arg,
        checkerboard_detector_node,
        image_view_node
    ])

のように,グリッド数(6x4)・グリッドの一辺長さ(20mm)を指定しているので checkerboard盤面の3次元位置姿勢は2次元画像から計算することができる. 格子パターンの右上緑線・赤線の部分の位置姿勢がROSのtopicとして取得できる.

2.8.3. チェックポイント2.10: checkerboardの認識#

チェックポイント 14 (checkerboardの認識)

Jedyを操縦しカメラ視界内にcheckerboardを入れ,正しく認識させよ. シミュレーションの場合はのいずれかの方法で台車を動かすとよい.

2.8.4. ROS/EusLispからの利用方法#

EusLispからcheckerboard認識結果を利用する例を紹介する.

$ roscd jedyeus/euslisp
$ roseus display-checkerboard.l

を実行すると格子パターンが見つかっていればのように EusLispのビューワ上のJedy相対の位置にcheckerboardの認識結果が表示される.

_images/checkerboard-detection.jpg

図 37 EusLispによるCheckerboard表示#


IRTビューワ(irtviewer)の操作方法

EusLispで3Dモデルを表示するirtviewerは,マウス操作で視点を自由に変更できる.

_images/jedy-on-irtviewer.jpg

図 38 IRTビューワに表示されたJEDYロボットの3Dモデル#

ビューワの更新方法:

  • ビューワウィンドウをクリックする

  • または,以下のプログラムを実行する:

irteusgl$ (send *irtviewer* :draw-objects)

ビューワのGUI操作:

  • 回転:画面中央付近でドラッグ

  • 上下移動:画面左部で上下にドラッグ(画面左部に見えないバーがあるイメージ)

  • 左右移動:画面下部で左右にドラッグ(画面下部に見えないバーがあるイメージ)

  • 拡大縮小:画面右部で上下にドラッグ(画面右部に見えないバーがあるイメージ)

これらの操作を使いこなすことで,ロボットの姿勢や認識結果を様々な角度から確認できる.

詳細な操作方法やプログラム例については,IRTビューワの操作方法を参照のこと.

jedyeus/euslisp/display-checkerboard.lをemacsや好きなEditorなどで開いてコードを見てみよう. コードの流れは概ね初期化部(ロボットモデルの作成,ros::roseus-add-msgsでROSのmsgのload)があり topicをsubscribeするためのコールバック関数がありdo-until-keyで回るようなメイン部分がある という点でこれまでに紹介したコードと同じ構成である.

コールバック関数の中の処理を見てみると(send msg :objects)でボード認識結果のlistを取得している. その後,ボードを表示する処理を行う.注意点としては,ボード位置姿勢を表す座標系は,カメラ相対の座標系として出力される. そのためEusLispworld座標系の値とするには座標変換を行う必要がある. コード中の次の部分が座標変換に該当する.

(let* (;; (1) カメラ相対の座標系は,geometry_msgs/Poseという型で得られるのでEusLispのcoordsに変換する
       (cam->obj-coords (ros::tf-pose->coords (send obj-pose :pose)))
       ;; (2) *jedy*モデルがカメラの座標系をもってるので取得する
       (cam-coords (send (send *jedy* :camera_color_optical_frame_lk) :copy-worldcoords)))
     ;; (3) EusLisp内部でのworld座標系の値にしてそこにcheckerboardモデルを配置する
     (send *target-object* :newcoords (send cam-coords :transform cam->obj-coords))
...

(1)認識結果が返すボード位置姿勢はカメラ相対であり (2)EusLisp上でのworld座標系でのカメラ座標系はEusLispの幾何モデルから計算できる. そのためイメージとしては(1)+(2)とした座標変換を施すことで (3)としてworld座標系でのボード位置姿勢を計算している.

Tip

ロボットの座標系とカメラの座標系の違いについては,ロボットの座標系とカメラの座標系を参照すること.

三次元点群処理

Important

本セクションはシミュレータ環境のみで対応

三次元点群処理の演習はGazeboシミュレータ環境でのみ実行可能である.実機では対応していないため,必ずシミュレーション環境で実施すること.

点群情報を使った三次元認識処理として色抽出を行い色付き点群をクラスタリングする方法を紹介する[7].

2.8.5. プログラムの起動#

重要:ROS 1環境の設定

hsi_color_filterはROS 1で実装されているため,必ず以下のコマンドでROS 1環境をsourceする必要がある.

$ source /opt/ros/one/setup.bash

この設定を忘れるとlaunchファイルが見つからないエラーが発生する.

三次元点群処理を実行するには,以下の4つのプログラムをそれぞれ別のターミナルで起動する必要がある:

  1. Gazeboシミュレータ

  2. BoundingBoxArrayのROS 2ブリッジpublish_robot_description.py

  3. ROS 1/ROS 2ブリッジros1_bridge

  4. 色抽出クラスタリングhsi_color_filter

以下,それぞれの起動手順を説明する.

2.8.5.1. 1. シミュレータの起動(ターミナル1)#

まず,Gazeboシミュレータを起動する.

$ source /opt/ros/jazzy/setup.bash
$ source ~/ros2_ws/install/setup.bash
$ ros2 launch jedy_bringup jedy_gazebo.launch.py

2.8.5.2. 2. BoundingBoxArrayのROS 2ブリッジ設定(ターミナル2)#

ROS 1のhsi_color_filterが出力するBoundingBoxArrayをROS 2側で利用するため,別のターミナルでpublish_robot_description.pyを起動する必要がある. このスクリプトはBoundingBoxArrayメッセージをROS 2にブリッジするための変換を行う.

$ source /opt/ros/jazzy/setup.bash
$ source ~/ros2_ws/install/setup.bash
$ ros2 run jedy_bringup publish_robot_description.py

Note

publish_robot_description.pyの役割

jedy_bringupパッケージのpublish_robot_description.pyは,ROS 1で出力されるBoundingBoxArrayメッセージをROS 2のトピックとしてブリッジするために必要な設定を行う.このスクリプトを起動することで,ROS 1とROS 2間でBoundingBox情報のやり取りが可能になる.

2.8.5.3. 3. ROS 2からROS 1へのトピックブリッジ(ターミナル3)#

ROS 2で動作しているカメラノード(Gazeboシミュレータ)からのトピックをROS 1のhsi_color_filterで受け取るには,ros1_bridgeを使用する必要がある.

# 別ターミナルでros1_bridgeを起動(ROS 2のトピックをROS 1に変換)
$ ros2 run ros1_bridge dynamic_bridge --bridge-all-topics

このコマンドにより,ROS 2の点群トピックがROS 1側でも利用可能になる.

2.8.5.4. 4. hsi_color_filterの起動(ターミナル4)#

# ROS 1環境をsource(重要!)
$ source /opt/ros/one/setup.bash

# シミュレーションでhsi_color_filterを起動
$ roslaunch jsk_pcl_ros hsi_color_filter.launch FILTER_NAME_SUFFIX:=_hsi INPUT:=/camera/depth/color/points

Tip

roslaunchの引数を確認する方法

ROS 1のlaunchファイルで利用可能な引数とそのデフォルト値を確認するには,--ros-argsオプションを使用する.

$ roslaunch jsk_pcl_ros hsi_color_filter.launch --ros-args
Required Arguments:
  FILTER_NAME_SUFFIX: undocumented
Optional Arguments:
  INPUT (default "hsi_input"): undocumented
  OUTPUT (default "hsi_output"): undocumented
  h_max (default "127"): undocumented
  h_min (default "-128"): undocumented
  s_max (default "255"): undocumented
  s_min (default "0"): undocumented
  i_max (default "255"): undocumented
  i_min (default "0"): undocumented
  ...

このようにして,launchファイルで設定可能なパラメータ(色抽出範囲やトピック名など)を確認できる.

ここで行っている処理は,点群を色に応じてフィルタリングしてユークリッド距離でクラスタリングし 抽出結果のBoundingBox (外接する直方体)のtopicを出すというものである. hsi_color_filter.launchをみるとROSノードとその間で通信されるtopicについて調べることができる. 代表的なtopicの流れは図.39である

_images/rqt-graph-hsi-color.png

図 39 rqt_graphによるhsi_filterノード#

まず,hsi_filterというROSノードが/remote/depth/color/pointsを受け取りHSI色空間で色抽出を行いhsi_outputとして点群データをpublishしている.最後に,euclidean_clusteringhsi_outputをsubscribeし点群をユークリッド距離でクラスタリングしている. cluster_decomposerは,クラスタ数の減少を行っており このノードがBoundingBoxArrayという型のtopicでカメラ相対の対象までの座標変換・サイズなどをpublishしている.

euclidean_clusteringcluster_decomposerは処理としては重い計算を要するためrostopic hzなどはかなり小さい値になる. また待機時の処理を減らすためsubscribeがされていないときは処理を行わない. そのため/HSI_color_filter/boxes_hsrがsubscribeされてるときだけ一連の処理が実行される.

2.8.6. Rvizによるデータ抽出過程の確認#

RVizを起動し(既に別で起動していればそれを利用して良い)PointCloud2型を追加する.操作の詳細は,前回の表示topicのRvizへの追加手順を参照のこと. 色抽出クラスタリングの過程で通信される

  • /camera/depth/color/points # Gazeboシミュレータから得られた点群

  • /HSI_color_filter/hsi_output_hsi # 色抽出フィルタリングした点群

の2種類のtopicを順に選んで表示が変わるか見てみよう. これら2種はいずれもPointCloud2型である(rostopic typeもしくはros2 topic typeを実行するとsensor_msgs/msg/PointCloud2と表示されることから確認できる).

色抽出などのパラメータは,hsi_color_filter.launchの中の以下に記述されている.

  <arg name="h_max" default="50" doc="..."/>
  <arg name="h_min" default="-20" doc="..." />
  <arg name="s_max" default="255" doc="..."/>
  <arg name="s_min" default="120" doc="..."/>
  <arg name="i_max" default="255" doc="..."/>
  <arg name="i_min" default="0" doc="..."/>

これらはroslaunchの引数で設定したり次節で説明するrqt_reconfigureで変更することができる. パラメータのうち,h_min, h_maxは,H (Hue, 色相)を制限するパラメータであり 今回は概ね赤色領域に限定している. これによりRviz上で下図のような点群が表示される.

_images/rviz_before_red_filters.jpg

図 40 赤色抽出前#

_images/rviz_after_red_filters.jpg

図 41 赤色抽出後#

2.8.7. rqt_reconfigureによるパラメータ動的変更#

ROSノードが立ち上がった後で動的にパラメータを変更することができればノードの立ち上げなおしが必要なく便利である. rqt_reconfigure[8] というパッケージを使うとGUIから対象となるノードやパラメータを指定して変更が可能である.

$ source /opt/ros/one/setup.bash
$ rosrun rqt_reconfigure rqt_reconfigure

を実行するとGUIが立ち上がる. GUIの左側に,reconfigureに対応したROSノードの候補が表示され,パラメータを変更したいROSノードを選択することができる. はhsi_filterを選択した場合である.

対応したパラメータを選択しスライダをずらしていくことで値を変更できる. はHSI色抽出フィルタでありそれぞれH, S, Iの最大値・最小値のスライダがある. 他にもrqt_reconfigureに対応している場合は,このGUIで値が設定できる. 例えばhsi_outputなどの色パラメータを変化させてみてrvizのhsi_outputの結果がどうかわるか確認してみよう.

_images/rqt_reconfigure_hsi_filter-all.jpg

図 42 rqt_reconfigureによるhsi_filterノードのパラメータ変更#

パラメータを変更したいノードが起動しているはずなのにrqt_reconfigure上にそれが現れない場合はrqt_reconfigureを再起動するとよい.

hsi_filterの他,euclidean_clusteringrqt_reconfigureでパラメータ設定可能である. rqt_reconfigure上でeuclidean_clusteringをたどるとmin_size(クラスタの最小点数)などが設定できる.

2.8.8. チェックポイント2.11: 色抽出とクラスタリング#

チェックポイント 15 (色抽出とクラスタリング)

色抽出プログラムhsi_color_filter.launchを起動し rqt_reconfigureを利用して色抽出パラメータを調節し 自分がターゲットにしたい特定の色の物体(赤色以外)を抽出しRviz上に表示させよう.

注意点:

  • パラメータ調整が完了したらそのパラメータをhsi_color_filter.launchに反映しておくとよい.

  • クラスタリングは重たい処理なので反映に時間がかかることに注意.

  • rqt_reconfigureからクラスタリング結果を変えられれば良い.

_images/hsi_before.jpg

図 43 rqt_reconfigureによるhsi_filterノードのパラメータ変更前#

_images/hsi_after.jpg

図 44 rqt_reconfigureによるhsi_filterノードのパラメータ変更後#

2.8.9. EusLispから結果を利用するサンプル#

色抽出クラスタリング結果を読み込むサンプルを実行しよう. 先ほどのhsi_color_filter.launchを起動しターミナルで

$ source /opt/ros/one/setup.bash
$ rosparam set /use_sim_time true  # シミュレーション環境のため必須
$ source ~/ros_ws/devel/setup.bash
$ roscd jedyeus/euslisp
$ roseus display-bounding-box-array.l

を実行するとEusLispのビューワ(irtviewer)上で赤色の直方体群(BoundingBox) が表示される(マウスで視点を変えるとよい).※キー入力でループ処理を抜けてインタプリタに処理が帰ってくるので注意.

jsk_pcl_ros/launch/hsi_color_filter.launchjedyeus/euslisp/display-bounding-box-array.lをemacsなど好きなエディタで開いてコードを見てみよう. hsi_color_filter.launchで起動するROSノードはjsk_pcl_ros (roscd jsk_pcl_rosで辿れる)というパッケージのROSノードである. EusLispのプログラムではそれら認識用msgの パッケージを利用するため (ros::roseus-add-msgs “jsk_recognition_msgs")を実行しsubscribeでコールバック関数の登録を行っている.

コールバック関数の中の処理を見てみると(send msg :boxes)BoundingBoxのlistを取得している.その後,各BoundingBoxを表示する処理を行う. 注意点としては,BoundingBoxの位置姿勢,カメラ座標系で出力される.そのためEusLispのworld座標系における位置姿勢になるようにcheckerboard認識器と同様の座標変換を行う.下図のような点群だとEusLispでは次のように表示される.

_images/euslisp-visualization-bounding-box.jpg

図 45 青色抽出領域のBoundingBoxをEusLispで取得して表示#

2.9. LLMを使用したロボットの自律操縦#

本節では,大規模言語モデル(LLM)を用いてロボットのカメラ画像を解析し,自然言語のプロンプトに基づいてロボットを自律的に操縦する方法を紹介する.LLMにカメラ画像と指示を与えることで,ロボットが環境を理解し適切な行動を選択できるようになる.

動画: LLMを使用してロボットが自律的にチェッカーボードのオブジェクトに接近する様子

Note

機械情報工学科3年生へ: HRI研究法入門で配布されたAPI_KEYを使用する場合は,環境準備のAPI KEY設定の手順でそのキーを使用すること.API KEYの新規発行が必要な場合は,Google AI Studio APIキーの発行 を参照のこと.

2.9.1. 環境準備#

LLMを使用するために必要なPython環境を構築する.

2.9.1.1. Python仮想環境の作成#

まず,プログラムが配置されているディレクトリに移動し,Python仮想環境を作成する.

$ cd ~/ros2_ws/src/robot-programming/jedy/jedy_bringup/scripts
$ python3 -m venv .venv

仮想環境を有効化する.

$ source .venv/bin/activate

仮想環境が有効化されると,プロンプトの先頭に(.venv)が表示される.

2.9.1.2. 必要なパッケージのインストール#

仮想環境内で必要なPythonパッケージをインストールする.

$ pip install langchain langchain-google-genai python-dotenv 'numpy<2' 'opencv-python<4.10'

2.9.1.3. API KEYの設定#

Google AI StudioのAPI KEYを環境変数として設定するため,.envファイルを作成する.

$ cd ~/ros2_ws/src/robot-programming/jedy/jedy_bringup/scripts

好きなエディタで.envファイルを作成し,以下の内容を記述する(your-api-key-hereの部分を実際のAPI KEYに置き換える).

GOOGLE_API_KEY=your-api-key-here

Warning

.envファイルには秘密情報(API KEY)が含まれるため,gitリポジトリにコミットしないよう注意すること.通常,.gitignoreファイルに.envが含まれている.

2.9.2. プログラムの起動#

LLMロボット操縦プログラムを使用するには,まずロボットを起動する必要がある.実機とシミュレーションで起動方法が異なる.

2.9.2.1. 実機#

$ ssh jedy@<ロボットPCのIPアドレス>
$ roslaunch jedy_ros1_bridge jedy_bridge.launch

2.9.2.2. シミュレーション#

シミュレーションでは,3つのターミナルを使用してシステムを起動する:

ターミナル1: ROS 1側でroscoreの起動

$ source /opt/ros/one/setup.bash
$ roscore

ターミナル2: ROS 2側でGazeboシミュレーションの起動

$ source /opt/ros/jazzy/setup.bash
$ source ~/ros2_ws/install/setup.bash
$ export ROS_AUTOMATIC_DISCOVERY_RANGE=LOCALHOST
$ ros2 launch jedy_bringup jedy_gazebo.launch.py

ターミナル3: ROS 1とROS 2のブリッジ

$ source /opt/ros/one/setup.bash
$ rosparam set /use_sim_time true
$ source /opt/ros/jazzy/setup.bash
$ source ~/ros2_ws/install/setup.bash
$ export ROS_AUTOMATIC_DISCOVERY_RANGE=LOCALHOST
$ ros2 run ros1_bridge dynamic_bridge --bridge-all-topics

Tip

シミュレーション中にロボットが倒れてしまった場合は,Gazebo Simulation の「ロボットが倒れた場合の復帰方法」を参照すること.

2.9.2.3. 実機・シミュレーション両方#

2.9.2.4. LLMロボット操縦プログラムの起動#

別のターミナルで,LLMを使用したロボット操縦プログラムを起動する.

$ cd ~/ros2_ws/src/robot-programming/jedy/jedy_bringup/scripts
$ source .venv/bin/activate
$ source /opt/ros/jazzy/setup.bash
$ source ~/ros2_ws/install/setup.bash
$ python3 robocrew_image_to_cmd_vel.py

プログラムが正常に起動すると,以下のようなログが表示される.

[INFO] [robocrew_image_to_cmd_vel]: RoboCrew Image to CmdVel node initialized
[WARN] [robocrew_image_to_cmd_vel]: No image received yet, skipping control loop

2.9.3. プロンプトの送信#

ロボットに指示を送るには,/robocrew/promptトピックにstd_msgs/msg/String型のメッセージを送信する.

別のターミナルを開き,以下のコマンドでプロンプトを送信する.

チェッカーボードを見つける例:

$ source /opt/ros/jazzy/setup.bash
$ ros2 topic pub --once /robocrew/prompt std_msgs/msg/String "{data: 'Find checkerboard'}"

緑色のオブジェクトに近づく例:

$ ros2 topic pub --once /robocrew/prompt std_msgs/msg/String "{data: 'Approach green object'}"

プロンプトを送信すると,ロボットはカメラ画像を解析し,LLMが適切な行動(前進,後退,左右回転,停止)を選択してロボットを操縦する.

2.9.4. RVizでのステータス表示#

ロボットの動作状態をRVizで視覚的に確認できる.

2.9.4.1. TextOverlayプラグインの追加#

RVizを起動する.

$ source /opt/ros/jazzy/setup.bash
$ source ~/ros2_ws/install/setup.bash
$ rviz2

RVizの左下にある「Add」ボタンをクリックし,「By display type」タブからrviz_2d_overlay_pluginsの中のTextOverlayを選択する.

_images/rviz-TextOverlay.png

図 46 RVizでTextOverlayプラグインを追加#

追加したTextOverlayの設定で,Topicを/robocrew/overlayに設定する.

2.9.4.2. ステータスの確認#

設定が完了すると,RVizの画面左上にロボットの動作状態が表示される.

_images/rviz-visualize-robocrew-status.png

図 47 RVizでRoboCrewのステータス表示#

表示される情報:

  • State: 現在の状態(ACTIVE,PROCESSING,EXECUTING,COMPLETED,ERRORなど)

  • Task: 実行中のタスク(プロンプトの内容)

  • メッセージ: 詳細な動作状況

2.9.5. プロンプトの例#

様々なプロンプトを試してロボットの動作を確認してみよう.

# チェッカーボードを探す
$ ros2 topic pub --once /robocrew/prompt std_msgs/msg/String "{data: 'Find checkerboard'}"

# 緑のオブジェクトまで近づく
$ ros2 topic pub --once /robocrew/prompt std_msgs/msg/String "{data: 'Approach green object'}"

# 青いオブジェクトを見つける
$ ros2 topic pub --once /robocrew/prompt std_msgs/msg/String "{data: 'Find blue object'}"

# 左に回転して周囲を探索する
$ ros2 topic pub --once /robocrew/prompt std_msgs/msg/String "{data: 'Turn left and explore surroundings'}"

プログラムの詳細はrobot-programming/jedy/jedy_bringup/scripts/robocrew_image_to_cmd_vel.pyを参照のこと.

2.9.6. パラメータ調整:シミュレーション速度への対応#

Tip

シミュレーション速度とLLM応答のタイミング調整

Gazeboシミュレーションの速度が速い場合,LLM APIの応答タイミングが実際のロボットの動作と合わなくなることがある. この場合,robocrew_image_to_cmd_vel.pyspeedパラメータを小さくすることで調整できる.

robocrew_image_to_cmd_vel.pyのファイルパス:

~/ros2_ws/src/robot-programming/jedy/jedy_bringup/scripts/robocrew_image_to_cmd_vel.py

ファイルを開いて,以下のようなspeedパラメータの値を変更する:

# デフォルト値(例)
speed = 0.2  # これを小さくする(例: 0.1, 0.05など)

速度を小さくすることで:

  • ロボットの移動速度が遅くなる

  • LLM APIの応答を待つ時間的余裕が生まれる

  • シミュレーション環境でも安定した動作が期待できる

シミュレーション環境の物理演算速度やマシンスペックに応じて,適切な値に調整すると良い.

2.10. 本日の発展課題#

2.10.1. 課題1(発展)#

シミュレーションで対応している部分のチェック項目のいずれかをGazebo環境で試してみよ.

2.10.2. 課題2(発展)#

複数PC間のROS通信を用いてロボットを動かしていない場合はにしたがって複数PC間のROS通信を行いながらいずれかのチェック項目を試してみよ. また,シミュレーション環境の場合も異なるPCから指令を送ったりセンサ値を観測したりできることを確認してみよ.

2.10.3. 課題3(発展)#

tmux・byobuにしたがってtmux・byobuコマンドを使ってプログラムの実行画面を複数PC間で共有してみよ. また,tmux・byobuコマンドがどのようなときに便利なのかを説明してみよ(TAチェックではTAに説明し課題提出時は同様の内容を文面で書く).

2.10.4. 課題4(発展)#

チェッカーボード認識や,ポイントクラウド認識を用いて Gazebo環境内の特定の物体を探索して移動・接近するような行動プログラムを作成せよ.

2.10.5. 課題5(発展)#

LaserScan(/scan)の値を用いて障害物を避けつつ移動するようなプログラムを作成せよ. (ヒント:/scanは前方-30 30度を640分割している)

2.10.6. 課題6(発展)#

SLAM・地図作成・自己位置推定を参考に,map作成や軌道計画を実行してみよう.

2.10.7. 課題7.1(発展)#

音声認識を利用して操縦せよ. 音声認識には,ros_speech_recognitionを使うと良い. ロボットPCでjedy_bridge.launchを立ち上げるか,jedy_gazebo.launch.pyを立ち上げたあとに,Zoomなどマイクを使用するプログラムを切った状態で以下のlaunchファイルを立ち上げる.

$ sudo apt install ros-one-ros-speech-recognition
$ source /opt/ros/one/setup.bash
# 英語で認識したい場合には
$ roslaunch ros_speech_recognition speech_recognition.launch
# 日本語で認識したい場合には
$ roslaunch ros_speech_recognition speech_recognition.launch language:=ja-JP

これでマイクに大きな声で進めや右,左などと喋りかけるとロボットが音声に応じて動くサンプルプログラムを実行できる.

/speech_to_textの出力結果はひらがなをutf-8形式で表示しているので注意すること.

$ source /opt/ros/one/setup.bash
$ rostopic echo /speech_to_text
transcript:
- "\u3053\u308C\u306F\u30C6\u30B9\u30C8\u3067\u3059"
confidence: [0.9184530377388]
transcript:
- "\u5DE6"
confidence: [0.9184530377388]

rostopic echomsgmという変数でとることのできる--filterオプションがあり,以下のようにすると日本語として見れる.

$ rostopic echo --filter "print(m.transcript[0])" /speech_to_text
これはテストです

また,ros2側へ送信するためにstd_msgs/msg/String型で

ros2 topic echo /speech_recognition_candidates_to_string/output

というトピックで出ている.

2.10.8. 課題7.2(発展)#

音声認識の結果をLLMプログラムとつなげることで発話からロボットへプロンプト指示をしてみよ.

2.10.9. 課題8(発展)#

これまでの授業や演習で学んだロボットプログラミング技法を組み合わせ, 自由な発想でロボットのデモプログラムを作成せよ.