Quantcast
Channel: demura.net
Viewing all 757 articles
Browse latest View live

Byobu:端末分割表示アプリ

$
0
0

Tmuxのキー操作を少し複雑なのでより簡単なByobuのインストールと使い方メモ。

公式サイト

公式Youtube:Learn Byobu while listening to Mozart

インストール

  • $ sudo apt install byobu

使い方

  • 起動:byobu
  • ヘルプ表示:Shift-F1
  • F2:作成/分割
    • ウインドウの作成:F2
    • ウインドウを上下に分割:Shift-F2
    • ウインドウを左右に分割:Ctrl-F2
    • 分割窓のリサイズ:Shift-Alt-Left/Right/Up/Down
  •  F3/F4:移動
    • ウインドウの移動:F3/F4
    • 分割窓の移動:Shift-F3/F4
  • F7:スクロールモード
    • スクロール:↑/↓
  • F12
    • マウスサポート:Alt -F12
  • 終了:exit

少し幸せになる設定

  • マウスサポートを常に有効にするために ~/.byobu/profile.tmuxの最後に次の1行を追加する。なお、マウスサポートをONにするとマウスを使ったコピペなどをする場合にbyobuと干渉するのでShiftキーを押しながらマウス操作をしなければならない。これ注意。
    • set -g mouse on


終わり


ROS2: Webotsシミュレータでルンバを動かそう!

$
0
0

ROS2でWebotsシミュレータでiRobot社のCreate2を動かしましょう!本記事ではカナダのSimon Fraser University, Autonomy Lab.のJacob PerronさんのフォークしたiRobot社のRoomba, Create2用のROS2ドライバー create2_autonomyを使います。なお、この記事はテストが十分ではなく、備忘録として執筆中です。エラーが出る場合があると思います。ご了承ください。


 

  • 参考サイト
  •  環境
    • Ubuntu20.04 
    • ROS2 Foxy
  • 準備
    • $ sudo apt update
    • $ sudo apt upgrade
    • $ sudo apt install -y python3-rosdep python3-colcon-common-extensions
    • $ sudo apt install build-essential python3-colcon-mixin python3-vcstool
  • Webotsのインストール
    • $ sudo apt install ros-foxy-webots-ros2
  • Create2関連パッケージのインストール
    • ワークスペースの生成
      • ディレクトリの作成
        • $ mkdir -p ~/airobo_ws/src
        • $ cd ~/airobo_ws
      • ビルド
        • $ colcon build
      • 設定ファイルの実行
        • $ source install/local_setup.bash
        • $ source install/setup.bash
    • ダウンロード
      • ディレクトリの移動
        • $ cd ~/airobo_ws/src
      •  libcreateのクローン(ダウンロード)
        • $ git clone https://github.com/RoboticaUtnFrba/libcreate.git
        • 上記のパッケージはROS1用でcolcon buildできなかったので以下に変更した。
          • git clone https://github.com/AutonomyLab/libcreate
      • create2_autonomyのクローン
        • $ git clone https://github.com/RoboticaUtnFrba/create2_autonomy.git
      • create2_hardwareのクローン
        • $ git clone https://github.com/RoboticaUtnFrba/create2_hardware.git
      • create2_utilitiesのクローン。これはiRobot Create2のグラフィカルとテストツール。
        • $ git clone https://github.com/RoboticaUtnFrba/create2_utilities.git
      • create2_descriptionのクローン。これはiRobotCreate2のWebots用のモデル記述パッケージ。
        • $ git clone https://github.com/RoboticaUtnFrba/create2_description.git
      • webots_ros2のクローン。ROS2のWebotsパッケージ。
        • $ git clone https://github.com/RoboticaUtnFrba/webots_ros2.git
    • 依存関係ファイルのインストール
      • 必要なパッケージのインストール
        • $ sudo apt install ros-foxy-image-pipeline 
        • $ sudo apt install bash-completion dirmngr gnupg2 lsb-release  ros-foxy-diagnostic-updater
        • $ pip3 install -U argcomplete flake8 flake8-blind-except flake8-builtins  flake8-class-newline flake8-comprehensions flake8-deprecated flake8-docstrings
        • $ pip3 install -U flake8-import-order flake8-quotes pytest-repeat pytest-rerunfailures
      • 他のファイルのインストール
        • $ cd ~/airobo_ws
        • $ rosdep update
        • $ rosdep install --from-paths src -yi
    •  ワークスペースのビルド
      • $ cd ~/airobo_ws
      • 私の環境では約3分でビルドが終了した。
        • $ colcon build 
      • 次のエラーがでる場合
        — stderr: webots_ros2_importer
        webots_simulation | error: package directory ‘webots_ros2_importer/urdf2webots/urdf2webots’ does not exist
        • 次のコマンドを実行する。
          • $ cd ~/airobo_ws/src/webots_ros2/webots_ros2_importer/webots_ros2_importer/urdf2webots
          • $ git clone https://github.com/cyberbotics/urdf2webots.git
          • $ cd urdf2webots
          • $ pip3 install -r requirements.txt
          • $ pip3 install urdf2webots
          • もう一度、ビルドと実行のコマンドを打つ。
      • 次のエラーが出る場合
        Starting >>> webots_ros2_core
        — stderr: webots_ros2_importer
        package init file ‘webots_ros2_importer/urdf2webots/urdf2webots/__init__.py’ not found (or not a regular file)
        • 次のコマンドを実行する。
          • $ cd ~/airobo_ws/src/webots_ros2/webots_ros2_importer/webots_ros2_importer/urdf2webots
          • $ cp ../../__init.py  .
  • 設 定
    • このワークショップに使う以下の設定を以下のコマンドにより、エディタgeditで.bashrcファイルを開き、末尾にコピペして保存する。
      • $ gedit  ~/.bashrc
source /opt/ros/foxy/setup.bash
source ~/airobo_ws/install/local_setup.bash
    •  以下のコマンドを実行して設定を反映させる。
      • $  source ~/.bashrc
  • 実 行
    • 新たに端末を開き、以下のコマンドを実行してシミュレータWebotsを起動する。一番下図のルンバをベースにしたロボットが現れる。ros1ではlaunchファイルの起動はroslaunchだったが、ros2ではros2  launchとros2とlaunchの間にスペースを入れる。launchファイルがxmlフォーマットの他にpythonでも書けるようになった。うまく実行されるとトップのような画像が表示される。
      • $ ros2 launch create2_description spawn_robot.launch.py 
    • 端末をもう一つ新たに開き、以下のコマンドを実行してGazebo上のルンバを遠隔制御する。ros1ではノードの実行はrosrunコマンドだったが、ros2ではros2  runコマンドとなる。これもros2とrunの間にスペースが必要。
      • $ ros2 run teleop_twist_keyboard teleop_twist_keyboard
      • 以下の画面になる。以下のキー操作でロボットを動かすことができる。なお、マウスのカーソルがこの2番目に開いた端末上にないとロボットは動かないので注意。
        • i: 前進、u:左前進、o:右前進
        • j: 左回転、k:停止、 l:右回転
        • m:左後進、,:後進、 .:右後進
        • スペース:停止
        • w/x:並進速度増速/減速(10%)
        • e/c:角速度増速/減速(10%)
    • 無事に動いたら成功。お疲れ様!

終わり

ROS2演習1-2021:ROS2 Foxyのインストールと設定

$
0
0

 

 

この記事は私が金沢工業大学ロボティクス学科で2020年度後学期に担当したロボットプログラミングⅡをROS2用に変更したものです。まずは、ROS2 Foxyをインストールして設定しましょう!作業時間はネットワーク環境によりますが、30分ほどで終わると思います。

環 境

  • Ubuntu 20.04  (64bit x86)
    • 本ページではIntelまたはAMDのCPU用のUbuntu20.04 (64bit x86)を対象とします。

参考サイト

準 備

  •  ROS2をインストールするためのサイト(リポジトリ)を追加
    • GPG公開鍵を利用するための設定
      • $ sudo apt update
      • $ sudo apt install curl gnupg2 lsb-release
      • $ sudo curl -sSL https://raw.githubusercontent.com/ros/rosdistro/master/ros.key -o /usr/share/keyrings/ros-archive-keyring.gpg
    • 次のようなエラーが出た場合
      • エラー:4 http://packages.ros.org/ros2/ubuntu focal InRelease
        公開鍵を利用できないため、以下の署名は検証できませんでした: NO_PUBKEY F42ED6FBAB17C654
      • 次のコマンドで解決する。なお、以下のキー番号は上のNO_PUBKEYと同じにする。
        • sudo apt-key adv –keyserver keyserver.ubuntu.com –recv-keys F42ED6FBAB17C654
    •  リポジトリの追加
      • $ echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/ros-archive-keyring.gpg] http://packages.ros.org/ros2/ubuntu $(lsb_release -cs) main" | sudo tee /etc/apt/sources.list.d/ros2.list > /dev/null

ROS2 のインストール

  • リポジトリを更新したのでアップデートする。
    • $ sudo apt update
  • インストールする。このインストールにより約3GBディスク容量が消費される。
    • $ sudo apt install ros-foxy-desktop

 

設 定

  • 設定スクリプトの反映。sourceコマンドはファイルにあるコマンドを現在のシェルで実行するコマンド。
    • $ source /opt/ros/foxy/setup.bash
  • 毎回、このコマンドを実行するのは面倒なので次のコマンドで~/.bashrcの最後の行に加える。
    • $ echo "source /opt/ros/foxy/setup.bash" >> ~/.bashrc

アプリのインストール

  •  Byobu。ROS2では多くの端末を開いて作業する必要があり、ノートPC画面の解像度が低いと作業効率が悪いので端末を分割表示するアプリByobuを使う。なお、Byobuは日本語の屏風が由来であり、内部でtmuxを使っているのでこれもインストールする。
    • $ sudo apt install  tmux  byobu
    • Byobuの設定:次の記事の「少し幸せになる設定」を行い、マウスサポートをONにする。
  •  ROS2ではビルドシステムがcatkinからcolconに変わった。別途インストールする必要がある。
    • $ sudo apt install python3-colcon-common-extensions
  • その他アプリのインストール
    • $ sudo apt install -y python3-argcomplete  python3-pip

テスト

  • ROS2がうまくインストールされたか、デモプログラムで確認する。まず、端末を開き、次のコマンドでByobuを起動する。
    • $ byobu
  • 起動したらShift+F2(シフトキーとF2キーを同時にを押す。そうすると下図のように端末が上下に分割される。
  • 端末の上領域をクリックして次のコマンドを打ち込む。まず、設定スクリプト(/opt/ros/foxy/setup.bash)を反映して、C++で作成されたtalkerプログラムを実行する。
    • $ source /opt/ros/foxy/setup.bash
    • $ ros2 run demo_nodes_cpp talker
  • 同様に、端末の下領域をクリックして次のコマンドを打ち込む。listenerはPythonで作成されている。
    • $ source /opt/ros/foxy/setup.bash
    • $ ros2 run demo_nodes_py listener
  • うまく実行されると、下図のようにtalkerが送信した情報をlistenerが受信して端末に表示される。

 

終わり

ROS2演習2-2021:亀で遊ぼう!

$
0
0

この記事は私が金沢工業大学ロボティクス学科で2020年度後学期に担当したロボットプログラミングⅡをROS2用に変更したものです。第1回でROS2をインストール、設定、動作を確認しました。第2回は、ROSの定番であるタートルシム(turtlesim)でROS2を体験してみましょう。なお、タートルは海亀のことでROSのマスコットで、Turtlesimは亀の2次元シミュレータです。この記事はROS2 Documentation Tutorialsの次の記事を改変しています。

参考サイト

インストールと確認

  • 次のコマンドでturtlesimパッケージをインストールする。パッケージはある目的のために作られたソフトウェア一式で一つのディレクトリにまとめられている。turtlesimパッケージは亀の2次元シミュレータに関するソフトウェア一式となっている。
    • $ sudo apt update
    • $ sudo apt install ros-foxy-turtlesim
  • インストールしたパッケージの実行可能ファイルを次のコマンドで確認しよう。
    • $ ros2 pkg executables turtlesim
  • 無事インストールされていれば次のようにdraw_square、mimic、turtle_teleop_key、turtlesim_nodeの4つの実行可能ファイルが表示される。表示されない場合はもう一度、インストールしてみよう。

実 行

  • では、端末を開き、次のコマンドでturtlesimを起動しましょう。
    • $ ros2 run turtlesim turtlesim_node

    • 端末には次のようにturtlesimのノード名/turtlesim、亀の名前 [turtle1]、姿勢(x, y, theta)が表示される。ノードはROSの実行中のプログラムで、Spawningのspawnは魚や蛙などが卵を生む意味であり、コンピュータゲームでキャラクタが登場する意味でも使われる。ここでは亀だけに2つをかけているのでしょうね。

亀を動かそう!

  • 端末を開き、次のコマンドでキー操作により亀を動かしましょう。次のコマンドでrunがノードを実行するコマンドで、turtlesimがパッケージ名、最後のturtle_teleop_keyが実行可能ファイル。
    • $ ros2 run turtlesim turtle_teleop_key
  • 端末には下図のように表示される。矢印キーで亀を動かすことができる。さっそく、矢印キーを押して亀を動かしてみましょう!亀が動くと動いた軌跡が白線で表示される。
  • 現在、実行されているノードを次のコマンドで確認しよう。ros2 runコマンドで実行したteleop_turtleとturtlesimノードが実行されていることがわかる。
    • $ ros2 topic list

GUI開発ツールrqt

  • ROSのQTペースのGUI開発ツールrqtをインストールして、さっそく使ってみましょう。
  • インストール
    • $ sudo apt update
    • $ sudo apt install ~nros-foxy-rqt*
  • 起動
    • 端末を開き、次のコマンドを実行する。次の空白のウインドウが開く。
      • $  rqt
  • 使い方
    • /killサービス:亀を消す/killサービスを実行しましょう。rqtのメニューPlugins→Services→Service callerをクリックすると色々なサービスが出てくる。その中の[/kill]を選択する。下図のように[Expression]を”turtle1″にして、右上の[Call]をクリックする。亀と軌跡の白線が消える。
    • /resetサービス:次にリセットする/resetサービスを同様にqtのメニューPlugins→Services→Service callerから選択して実行する。次のようにまた、turtle1が画面中央に現れる。端末には次のようにturtlesimがリセットされたことと、turtle1の姿勢が表示される。
    • /spawnサービス:新しい亀を生成する/spawnサービスを実行しましょう。同様にして、rqtのメニューPlugins→Services→Service callerを選択して、/spawnサービスを選択する。次のように設定して、[Call]をクリックして新しい亀を誕生させましょう。下図のように中央より少し右下に新しい”kame”が誕生する。
      • x:  7.0
      • y:   4.0
      • theta: 3.14
      • name: “kame”
    • /set_penサービス:軌跡の色を変更する/set_penサービスを使ってみよう。[Service]を”/turtle1/set_pen”を選ぶ。turtle1がない場合は[Service]の左の[ボタン]をクリックする。黄色で線の太さ10になるようにExpressionを次のように変更する。では、上で亀を動かしたようにturtle_teleop_keyノードを使って、適当に亀を動かして軌跡の色と太さが変わるのを確認する。
      • r: 255
      • g: 255
      • width: 10
    • /clearサービス:亀の軌跡を消す。
  • リマップ
    • トピック名を付け替えるリマップを使い、先程動かしたturtle_teleop_keyを使って新しく生成したkameを動かしてみましょう。新しい端末を開き次のコマンドを実行する。
      • $ ros2 run turtlesim turtle_teleop_key --ros-args --remap turtle1/cmd_vel:=kame/cmd_vel
  • 終 了
    • では、turtlesimを終了させましょう。TurtleSimウインドウの[☓]をクリックするか、起動した端末でCtrl-C(コントロールキーを押しながらCキーを押す)を押すとノードが終了する。turtle_teleop_keyノードを終了させるときは、それを実行した端末でCtrl-Cを押すか、qキーを押す。
    • 今回の記事はこれで終わりです。お疲れ様!

終わり

 

 

 

 

 

 

 

 

終わり

 

ROS2演習3-2021:はじめてのROS2プログラミング

$
0
0

この記事は私が金沢工業大学ロボティクス学科で担当している2020年度後学期に担当したロボットプログラミングⅡをROS2用に変更したものです。演習3では次のコンテンツを学びます。

コンテンツ

  • ワークスペース
  • パッケージ

参考サイト

 

ワークスペース

  • 概要
    • これからROS2でいろいろなプログラムを作っていきます。ROS2ではプログラムをパッケージ(package)とよばれる単位で作っていきます。まずは、パッケージを保存する作業用のディレクトリ(フォルダ)を作りましょう。ROS2ではこれをワークスペース(workspace)とよびます。1つのワークスペースに好きなだけパッケージを作ることができます。端末でパッケージを使うためには、設定ファイルを反映する必要があります。
    • まず、既にインストールされているROS2の設定ファイルを反映します。これは、これから新規に作成するワークスペースのパッケージをビルドするために必要です。この環境のことをアンダーレイ(underlay)とよびます。一方、これから新規に作成するワークスペースの環境をオーバーレイ(overlay)とよびます。オーバーレイはアンダーレイをもとにした環境です。
  • 設定ファイルの実行
    • 次のsourceコマンドでアンダーレイの設定ファイル/opt/ros/foxy/setpu.bashを実行します。sourceはファイルに書かれたコマンドを現在のシェルで実行するコマンドです。
      • $ source /opt/ros/foxy/setup.bash
  •  ワークスペース用ディレクトリの作成
    • 次のコマンドで名前がworkspace_nameのワークスペースに使用するディレクトリを作成します。ディレクトリ名は何でもよい。先頭の$は入力を受け付けるコマンドプロンプトなので打つ必要はありません。
      • $ mkdir -p ~/workspace_name/src

パッケージ

  • 概要
    • パッケージはあなたが作成したROS2コードの入れ物と考えることもできます。パッケージを使うことにより、あなたのROS2コードを簡単に公開したり、ビルドできるようになります。
  • 種類
    • ROS2ではビルドシステムとしてamentを使い、ビルドするツールとしてcolconを使います。パッケージの種類はCMakeとPythonがあります。CMakeはソフトウェアをビルド、テストするツールでCやC++のビルドに使われます。
  • 構成
    • CMake:次のファイルが必須
      • CMakeLists.txt:パッケージのコードをビルドする方法が書かれたファイル
      • package.xml:パッケージに関するメタ情報が書かれたファイル
    • Python
      • setup.py:パッケージのインストールする方法が書かれたファイル
      • setup.cfg:パッケージに実行可能ファイルがある場合に必要なファイル。ros2 runコマンドが実行可能ファイルを見つけるのに使う。
      • package.xml:パッケージに関するメタ情報が書かれたファイル
      • /<package_name>:パッケージと同じ名前のディレクトリ。ROS2のツールがパッケージに__init__.pyがあるかを見つけるのに使う。
  • 作成
    • ディレクトリを移動する。
      • $ cd ~/colcon_ws/src
    • 次のros2 pkg createコマンドで名前がpackage_nameのパッケージを作成する。
      • CMake
        • $ ros2 pkg create --build-type ament_cmake <package_name>
      • Python
        • $ ros2 pkg create --build-type ament_python <package_name>
      • ROS2のプログラムを作成する。典型的なROS2プログラムは次の処理をしている。
        1. 初期化
          • rclpy.init(): ROS2通信のための初期化。ROS2ノード作成する前に呼び出さなければならない。
        2. ROS2ノードの作成
          • rclpy.create_node()関数を呼び出すか、Nodeクラスからインスタンスを作成するかどちらかの方法で作成する。通常はクラスを使ってプログラムを作成するので後者の方法を選ぶ。
        3. ノードの処理(コールバック関数を使う場合が多い)
          • 次の関数でノードを処理を実行する。
            • rclpy.spin():処理を実行して、ノードが終了するまでブロックする。
            • rclpy.spin_once():処理を1回実行するか、タイムアウトの期限までウェイトする。
        4. 終了処理
          • rclpy.destroy_node():ノードを破壊する。
          • rclpy.shutdown():初期化コンテキストを終了する。
      • なお、簡単に説明した初期化や終了処理のAPIは以下のリンクで詳細がわかる。
  • ビルド
    • ROS2ではビルドツールにcolconを使う。
      • ビルドするためにworkspace_nameディレクトリに移動する。
        • $ cd ~/workspace_name
      • 次のcolconコマンドでビルドする。このコマンドではワークスペースにある全てのパッケージをビルドする。
        • $ colcon build
      • ワークスペースで初めてビルドすると~/workspace_nameディレクトリにbuild、install、logディレクトリが作成される。
      •  次回以降、1つのパッケージmy_packageだけビルドしたいときは次のpackages-selectオプションをつけてビルドする。
        • $ colcon build --packages-select my_package
  • 設定ファイルの実行
    • アンダーレイ設定ファイルの実行
      • $ source /opt/ros/foxy/setup.bash
    • オーバーレイ設定ファイルの反映。作成したワークスペースの設定ファイルを実行する。これにより、あなたのワークスペースがパスに追加されるので、パッケージの実行可能ファイルを使うことができるようになる。
      • $ source ~/workspace_name/install/setup.bash
  • パッケージの実行
    • ros2 runコマンドで、パッケージ名my_package、ノード名my_nodeを実行する。
      • $ ros2 run my_package my_node

ハンズオン

A. 一連の作業体験
では、ワークスペース作成からパッケージ作成と実行までの一連の流れを体験しましょう!なお、この例ではワークスペース名をcolcon_ws、Pythonパッケージとしています。

  1. ワークスペースの作成と移動
    • $ mkdir -p  ~/colcon_ws/src
    • $ cd ~/colcon_ws/src
  2. アンダーレイ設定ファイルの実行
    • $ source /opt/ros/foxy/setup.bash
  3. パッケージとノード作成。--node_nameオプションをつけるとプログラミングの最初の定番例hello worldと端末に出力するサンプルが作られる。ここではノード名をhello_node、パッケージ名をhelloにする。
    • $ ros2 pkg create --build-type ament_python --node-name  hello_node  hello
    • パッケージがうまく作られたか確認しよう。次のlsコマンドを実行して、下図のようにhello、resource、testディレクトリとpackage.xml、setup.cfg、setup.pyファイルができていれば成功。lsコマンドに-Fオプションをつけているので、ディレクトリの場合は最後に/がついて表示される。
      • $ ls -F  ~/colcon_ws/src/hello
  4. ビルド
    • $ cd  ~/colcon_ws
    • $  colcon build
  5. オーバーレイ設定ファイルの実行
    • $ source ~/colcon_ws/install/setup.bash
  6. ノードの実行
    • $ ros2 run hello  hello_node
    • 問題がなければ次のように端末に表示される。
      • Hi from hello.
  7. 少し幸せになる設定
    • 毎回、アンダーレイとオーバーレイの設定ファイルを実行するのは面倒なので次のコマンドを実行して.bashrcに追記する。
      • $ echo "source /opt/ros/foxy/setup.bash" >> ~/.bashrc
      • $ echo "source ~/colcon_ws/install/setup.bash" >> ~/.bashrc

 

B. 初めてのROS2プログラム作成

次に、上で作成したhelloパッケージを改変して初めてのROS2のプログラムを作って行こう!

  • ソースコードの作成
    • $ cd ~/colcon_ws/src/hello/hello
    • $ gedit hello_node.py
      • 上の作業で自動的に作成されたhello_node.pyは次図のようになっている。1行目のmain関数は端末に’Hi from hello.’を表示する。ここで5行目はこのコードをモジュールとしてimportできるようにするおまじない。詳しくはネットで調べてみよう!
      • では、このhello_node.pyを次のコードで置き換えよう。コードにコメントがあるので、それを読んで理解する。
  • import rclpy # ROS2のPythonモジュールをインポートする
    import time  # スリープに使用するtimeモジュールのインポート
    from rclpy.node import Node # rclpy.nodeからNodeモジュールをインポートする
    
    # 端末にhello worldと10回表示する関数        
    def print_hello():
        i = 1
        while i <= 10:
            print('%d: hello world' % i)
            i += 1
            time.sleep(1) # 1秒間スリープする
    
    # main関数
    def main():
        rclpy.init()               # ROS通信の初期化
        node = Node('hello_node')  # ノードの生成。引数はノード名。
        print_hello()              # 自作関数
        rclpy.spin(node)           # ノード終了まで待機
        rclpy.destroy_node()   # ノードの破壊
        rclpy.shutdown()           # ノードの終了処理
    
    # このコードをモジュールとしてimportできるようにするおまじない。
    if __name__ == '__main__':
        main()    
    

 

  • Package.xmlファイルの編集
    • 自動作成されたPackage.xmlを次に示す。ここで、変更する必要があるのは次の5項目。現時点では必要ないが、自作パッケージを公開するときは変更しましょう。
      • 4行目:name (パッケージ名)
      • 5行目:version(パッケージのバージョン)
      • 6行目:description (パッケージの説明)
      • 7行目:maintainer email (保守者、メールアドレス)
      • 8行目:license (パッケージのライセンス)

  • Setup.pyファイルの編集
    • 自動作成されたSetup.pyを次に示す。ここで、変更する必要があるのは次の6項目。この内容は、Package.xmlと同じにしなければならない。
      • 3行目:package_name (パッケージ名)
      • 7行目:version(パッケージのバージョン)
      • 16行目:maintainer (保守者)
      • 17行目:maintainer_email (保守者のメールアドレス)
      • 18行目:description (パッケージの説明)
      • 23行目
        • ‘ノード名 = パッケージ名.ノード名:main’

  • ビルド
    • $ cd  ~/colcon_ws
    • $  colcon build
  • オーバーレイ設定ファイルの実行
    • $ source ~/colcon_ws/install/setup.bash
  • ノードの実行
    • 次のコマンドを実行して、下図のようにhello worldが表示されれば成功! 10: hello worldと表示されたらプログラムがブロックされるのでCtrl-Cでノードを終了させる。
      • $ ros2 run hello  hello_node

ホームワーク

  • helloパッケージのhello_node.pyプログラムをクラス化した次のコードを使い、hello2パッケージを作成して実行しよう。

  •  以下のノードを作成しよう!
    • “I Love KIT”と表示するkitノードを作ろう。ただし、ダブルクォーテーションは表示しなくて良い。
    • キーボードから打たれ文字列をそのまま表示するechoノードを作ろう。ただし、文字列に空白は含まないとものとします。
    • キーボードから打たれた文字列を”I Love”の後につける、loveノードを作ろう。

終わり

ROS2演習4-2021:シミュレータでTurtlebot3を動かそう!

$
0
0

この記事は私が金沢工業大学ロボティクス学科で担当している2020年度後学期に担当したロボットプログラミングⅡをROS2用に変更したものです。今回は、シミュレータGAZEBOを使い、Turtlebot3を動かします。次のTurtleBot3 e-Manualを参考にしています。

1. 準 備

  • これからの演習で必要になるパッケージを次のコマンドでインストールします。
    • Gazeboのインストール
      • $ sudo apt install gazebo11 ros-foxy-gazebo-ros-pkgs
    • Cartographerのインストール
      • $ sudo apt install ros-foxy-cartographer
      • $ sudo apt install ros-foxy-cartographer-ros
    •  Navigation2のインストール
      • $ sudo apt install ros-foxy-navigation2
      • $ sudo apt install ros-foxy-nav2-bringup
    •  Turtlebot3関連パッケージのインストール
      • $ source ~/.bashrc
      • $ sudo apt install ros-foxy-dynamixel-sdk
      • $ sudo apt install ros-foxy-turtlebot3-msgs
      • $ sudo apt install ros-foxy-turtlebot3
      • $ cd ~/colcon_ws/src
      • $ git clone -b foxy-devel https://github.com/ROBOTIS-GIT/turtlebot3_simulations.git
      • $ cd ~/colcon_ws
      • $ colcon build --symlink-install

2. 設 定

geditを使って~/.bashrcの最後(124行)に次の1行を追加して保存する。exportは環境変数を設定するコマンド。ここでは、TURTLEBOT3_MODELをburgerに設定している。なお、上の準備でインストールしたTurtlebot3パッケージには、ロボットがburger、waffle、waffle_piの3種類ある。ここでは、一番シンプルなburgerを選択する。burgerは私の研究室にも3台ある。

  • export  TURTLEBOT3_MODEL=burger

  • 設定を反映するためにsourceコマンドを実行する。
    • $  source ~/.bashrc

3.  Simulator GAZEBOを動かそう

次のコマンドでROS2のシミュレータGazeboを起動する。

  • $ ros2 launch turtlebot3_gazebo empty_world.launch.py

初回の起動はネットからモデルを取得するので、私の環境で5分程度かかった。しばらくすると次のようなウインドウが開く。図の青い円はLIDARが到達する範囲を示している。シミュレータの環境がempty_worldだけにロボット以外は何も存在しない環境である。格子が1辺1mなのでBurgerが搭載しているLIDARは3.5m届く。マウスでドラッグするとシミュレータの視点を変えることができる。下の画面が拡大してBurgerを表示したもの。実際のBurgerよりモデルが単純化されているのは残念。

  • 左マウスボタンをドラッグ:視点の平行移動
  • マウスホイールをスクロール/右マウスボタンをドラッグ:拡大、縮小
  • マウスホイールをドラッグ:視点の回転

次に、別の端末を開き、次のコマンドを入力するとキーボードからロボットを操縦するためにturtlebot3_teleopパッケージのteleop_keyboardノードを起動する。

  • ros2 run turtlebot3_teleop teleop_keyboard

端末に下のように表示される。w a s d x キーでロボットを操作できる。いずれかのキーを押してロボットを動かそう!マウスのカーソルがturtlebot3_teleop_key.launchを起動した端末上になければ動かないので注意。

  • w:前進。増速
  • a:左回転。増速
  • s/スペースキー:ストップ
  • d:右回転。減速
  • x:後進。減速。

お疲れ様!

ROS2演習5-2021:トピック通信しよう!(Python)

$
0
0

この記事は私が金沢工業大学ロボティクス学科で担当している2020年度後学期に担当したロボットプログラミングⅡをROS2用に変更したものです。今回は、ROS2の通信方式であるトピックとそれをPythonで実現する方法を学びましょう!詳細なコンテンツは次のとおりです。

コンテンツ

  • トピック通信

参考サイト

概 要

  • ROS2の通信方式にはトピック通信サービス通信があり、トピック通信は1対多(一つのノードから多くのノードに通信可能)の非同期通信で、メッセージ通信は1体1(一つのノードからはある特定のノートにしか通信できない)の同期通信です。ここではトピック通信を学びます。トピック通信では送り手と受け手がTopic(トピック)とよばれる名前付きのバス(伝送路)を介してデータをやり取りしています。送り手のことをPublisher(配信者)、受け手のことをSubscriber(購読者)、データのことをメッセージとよびます。

準 備

  • 以下の演習を実施していない場合は、実施して必要なパッケージをインストールしてシミュレータの使い方を学ぶ。
  • 端末を開き、byobuを実行して、端末を上下に3分割する。
    • $ byobyu
    • Shift+F2キーを押すと端末を上下に2分割される。
    • もう一度、Shift+F2キーを押すと端末が全部で上下に3分割される。
    • Shift-Alt-上下キーで端末のサイズを調整する。

パブリッシャ (Publisher)

  1.  ソースコードと説明:キーボードからロボットを操縦するmy_teleopパッケージを作ろう!
    ROS2演習3と同じ要領でmy_teleopパッケージを作る。今回の例ではパッケージ名helloをmy_teleop、ノード名をmy_teleop_nodeとする。1番目の端末で次のコマンドを実行して、my_teleopパッケージとmy_teleop_nodeノードを作成する。
    • $ cd ~/colcon_ws/src
    • $ ros2 pkg create --build-type ament_python --node-name my_teleop_node my_teleop

このプログラムはメッセージの送リ手であるpublisher(配信者)プログラムの簡単な例にもなっている。プログラムの説明はソースコード内のコメントを参照して欲しい。好きなテキストエディタにコピペしてmy_teleop_node.pyと名前を付けて、~/colcon_ws/src/my_teleop/my_teleopディレクトリに保存する。以下の例ではgeditを使っている。

    • $ cd ~/colcon_ws/src/my_teleop/my_teleop
    • $ gedit my_teleop_node.py  &
#  ファイル名 my_teleop_node.py
import rclpy  # ROS2のPythonモジュールをインポート
from rclpy.node import Node # rclpy.nodeモジュールからNodeクラスをインポート
from std_msgs.msg import String # トピック通信に使うStringメッセージ型をインポート
from geometry_msgs.msg import Twist # トピック通信に使うTwistメッセージ型をインポート


class TeleopPublisher(Node): 
    """タイマーのコールバック関数を使い、ロボットを動かす速度指令値のトピックcmd_vel
    をパブリッシュするクラス。
    
    Node: TeleopPublisherクラスが継承するクラス    
    """

    def __init__(self):
        """コンストラクタ。パブリッシャーとタイマーを生成する。
        """
        # Nodeクラスのコンストラクタを呼び出し、'teleop_pulisher_node'というノード名をつける。
        super().__init__('teleop_publisher_node') 
        # パブリッシャーの生成。create_publisherの1番目の引数はトピック通信に使うメッセージ型。
        # Twist型は速度指令値を通信するのに使われる。2番目の引数'cmd_vel'はトピック名。
        # 3番目の引数はキューのサイズ。キューサイズはQOS(quality of service)の設定に使われる。
        # サブスクライバーがデータを何らかの理由で受信できないときのキューサイズの上限となる。
        self.publisher = self.create_publisher(Twist,'cmd_vel', 10)
        
        # タイマーの生成。タイマーのコールバック関数timer_callbackをtimer_period間隔で実行する。
        # この例では0.01[s]秒ごとにtimer_callback関数を呼び出す。
        timer_period = 0.01  # 秒
        self.timer = self.create_timer(timer_period, self.timer_callback)
        
        # Twistメッセージ型オブジェクトの生成。メンバーにdVector3型の並進速度成分linear、
        # 角速度成分angularを持つ。        
        self.vel = Twist()
        print("*** my_teleop node ***")
        print("Input f, b, r, l  key, then press Enter key.")
        
                
    def timer_callback(self): 
        """タイマーのコールバック関数。入力キーにより並進及び角速度を増減している。
        input関数はブロックされるので、キーを入力した後にEnterキーを押さなければ速度は変更されない。
        """
        key = input("f:forward, b:backward, r:right, l:left, s:stop <<")
        print("key=", key)
           
        # linear.xは前後方向の並進速度(m/s)。前方向が正。
        # angular.zは回転速度(rad/s)。反時計回りが正。
        if key == 'f': # fキーが押されていたら
            self.vel.linear.x  = 0.25
        elif key == 'b':
            self.vel.linear.x   = -0.25
        elif key == 'l':
            self.vel.angular.z  = 0.25
        elif key == 'r':
            self.vel.angular.z  = -0.25
        else:
            print("Input f, b, r, l : ") 
   
        self.publisher.publish(self.vel) # 速度指令メッセージをパブリッシュ(送信)する。
        # 端末に並進と角速度を表示する。
        self.get_logger().info("Velocity: Linear=%f angular=%f" % (self.vel.linear.x,self.vel.angular.z)) 
   
def main(args=None):
    rclpy.init(args=args) # rclpyモジュールの初期化
    teleop_publisher = TeleopPublisher() # ノードの作成
    rclpy.spin(teleop_publisher) # コールバック関数が呼び出し
    rclpy.shutdown() # rclpyモジュールの終了処理

if __name__ == '__main__':
    main()

ここで、馴染みのないコールバック関数callbackが登場しています。コールバック関数はIT用語辞典によると「コールバック関数とは、プログラム中で、呼び出し先の関数の実行中に実行されるように、あらかじめ指定しておく関数。」と定義されています。通常はマウスで線を描くなどの処理を実装するような、あるイベントが起きた時に処理をするプログラムを実装する場合に使われます。通常は、マウスのイベント処理などの場合のようにマウスのボタンが押されたり、移動したときに自動的にコールバック関数が呼び出されますが、ROSではspinOnce()やspin()で明示的に呼び出さなければいけません。spinOnce()はコールバック関数を一度だけ呼び出すので通常はwhileループの中で使います。spin()はノードが動いている間、コールバック関数を呼び続けます。ROSではメッセージの受け渡しにコールバック関数を使います。

   2.ビルド

    • 1番目の端末で以下のコマンドでビルドしよう。
      • $ cd ~/colcon_ws
      • $ colcon build 


       3. 実行

    • 1番目の端末で次のコマンドを実行して、my_teleopノードを実行する。
      • $ ros2 run my_teleop my_teleop_node
    •  2番目の端末で次のコマンドを実行して、gazeboを起動する。
      • $ export TURTLEBOT3_MODEL=burger
      • $ ros2 launch turtlebot3_gazebo empty_world.launch.py

サブスクライバ (Subscriber)

  1. ソースコードと説明

次に、メッセージの受け手であるsubscriber(購読者)の簡単なプログラムを示します。このプログラムはmy_teleop_nodeがパブリッシュするトピックcmd_velをサブスクライブして、並進速度(Linear Velocity)と角速度(Angular Velocity)を標準出力に出力する簡単なプログラムです。

# ファイル名 my_subscriber_node.py
import rclpy  # ROS2のPythonモジュールをインポート
from rclpy.node import Node # rclpy.nodeモジュールからNodeクラスをインポート
from std_msgs.msg import String # トピック通信に使うStringメッセージ型をインポート
from geometry_msgs.msg import Twist # トピック通信に使うTwistメッセージ型をインポート


class MySubscriber(Node): 
    """速度指令値のトピックcmd_velをサブスクライブして端末に表示するたけの簡単なクラス    
    """
    def __init__(self):
        """コンストラクタ。サブスクライバーを生成する。
        """
        # Nodeクラスのコンストラクタを呼び出し、'my_subscriber_node'というノード名をつける。
        super().__init__('my_subscriber_node') 
        # サブスクライバーの生成。create_subscriptionの1番目の引数Twistはトピック通信に使うメッセージ型。        
        # Twist型は速度指令値を通信するのに使われる。2番目の引数'cmd_vel'はトピック名。
        # 3番目の引数はコールバック関数。 4番目の引数はキューのサイズ。
        self.subscription = self.create_subscription(Twist,'cmd_vel', self.listener_callback, 10)
   
               
    def listener_callback(self, Twist): 
        """サブスクライバーのコールバック関数。端末に並進と角速度を表示する。
        """
        self.get_logger().info("Velocity: Linear=%f angular=%f" % (Twist.linear.x,Twist.angular.z)) 
   
   
def main(args=None):
    rclpy.init(args=args)          # rclpyモジュールの初期化
    my_subscriber = MySubscriber() # ノードの作成
    rclpy.spin(my_subscriber)      # コールバック関数が呼び出し
    my_subscriber.destory_node()   # ノードの破壊
    rclpy.shutdown()               # rclpyモジュールの終了処理

if __name__ == '__main__':
    main()

では、my_subscriber_nodeを作ろう。

好きなテキストエディタにコピペしてmy_subscriber_node.pyと名前を付けて、~/colcon_ws/src/my_teleop/my_teleopディレクトリに保存する。以下の例ではgeditを使っている。

  • $ cd ~/colcon_ws/src/my_teleop/my_teleop
  • $ gedit my_subscriber_node.py  &

2.  依存関係の追加

my_teleopパッケージを作成したので~/colcon_ws/src/my_teleopディレクトリに setup.py、setup.cfg、package.xmlが作られている。package.xmlの5行から7行を必要に応じて変更する。次に、依存関係を示す10行目から12行目を追加する。この3つのモジュールはソースコードでインポートしており、実行時に必要になる。

   3.   エントリポイントの追加

次に、setup.pyをエディタで開いて、エントリポイントとなる次の1行を24行目に挿入する。エントリーポイントには実行するファイルと関数を指定する。23行目に関しては、パッケージを作成するときにノード名my_teleop_nodeを指定したので自動で作られた。

    • ‘my_subscriber_node = my_teleop.my_subscriber_node:main’,

4. Setup.cfgのチェック

setup.cfgは自動作成される。このファイルにはros2 runで使う実行可能ファイルがどこにあるかが書かれている。 

 5. ビルドと実行

ROS2をインストールしたときに依存関係のあるrclpy、std_msgs、geometry_msgsは既にインストールされているが、依存関係を解消する便利なコマンドを紹介する。足りないパッケージがあれば探してインストールしてくれる。

  • $ cd ~/colcon_ws
  • $ rosdep install -i --from-path src --rosdistro foxy -y

では、以下のコマンドでビルドして実行しよう。

  • $ cd ~/catkin_w
  • $ catkin build my_subscriber 
  • $ rosrun my_subscriber my_subscriber_node

 6. シミュレータでの確認

  • 端末を3つ開く。
  • 1番目の端末でシミュレータを起動する。
    • $  ros2 launch turtlebot3_gazebo empty_world.launch.py
  • 2番目の端末でmy_teleop_nodeノードを起動する。
    • $ ros2 run my_teleop my_teleop_node
  • 3番目の端末でmy_subscriberノードを起動する。
    • $ rosrun my_teleop my_subscriber_node
  • 次にmy_teleopノードを起動した端末にマウスカーソルを持って行く。
    f, b, l, rキーでロボットが移動し、sキーで停止したら成功。キーを押した後はエンターキーを押さないと動かない。
  • 最後に、my_subscriber_nodeノードを起動した端末を見ましょう。速度が表示されていたら成功。

お疲れ様!

ホームワーク

  1. キーsを押すと、ロボットが停止するようにmy_teleop_node.cppのソースコードを変更しよう!
  2. my_teleop_node.cppではキーボードのf, b, r, lを押した後にエンターキーを押すと、一定の速度でロボットが動き出す。キーを押すたびに並進速度が0.01 [m/s]ずつ増減、回転角度が0.1 [rad/s]ずつ変化するようにソースコードを変更しよう!
  3. 指定した時間[s]だけ、指定した速度[m/s]と角速度[rad/s]で移動するプログラムを作ろう!
  4. ロボットの移動する軌跡が1辺x[m]の正方形になるようプログラムを変更しよう!
  5. ロボットの移動する軌跡が半径x[m]の円になるようプログラムを変更しよう!
  6. my_teleop_node.pyは、ROS2演習4-2021:シミュレータでTurtlebot3を動かそう!teleop_keyboardとは違いf, b, r, lのキーを押した後にエンターキーが必要です。エンターキーを押さずに、f, b, r, lキーを押すとロボットが移動するようにソースコードを変更しよう。なお、my_teleop_node.pyではinput関数でキーボードから入力しますがキーが入力されるまで待状態になります。これをブロックとよびます。エンターキーが入力されると次の処理に移ります。Linuxでブロックしない入出力をpythonで実現する方法を調べて実装しよう!

終わり

ROS2演習6-2021:簡単なサービス通信しよう!(Python)

$
0
0

この記事は私が金沢工業大学ロボティクス学科で担当している2020年度後学期に担当したロボットプログラミングⅡをROS2用に変更したものです。今回は、ROS2のもう一つの通信方式であるサービスとそれをPythonで実現する方法を学びましょう!

コンテンツ

  • サービス通信

参考サイト

概 要

サービス(service)はROSの通信方法の一つで、双方向通信に使います。ある仕事をお願いするクライアント(client)とそれを処理して返すサーバー(server)からなります。今回、作成する簡単なプログラムは、[ROS2演習20-2021:亀で遊ぼう!]でrqtで使ったspawnサービスをサーバーにリクエスト(request、要求)するクライアントとそれに対して亀の名前をリスポンド(respoint、応答)するサーバーです。リクエストとリスポンドは.srvファイルで決まります。次の手順でやります。

  1. パッケージの作成
  2. サーバーノードの作成
  3. クライアントノードの作成

ハンズオン

1.パッケージの作成

ROS2演習3-2021でパッケージを作ったように、~/ワークスペース名/srcディレクトリに移動し、ros2 pkg createコマンドでsimple_serviceパッケージとsimple_serverノードを作成する。今回新しく出た--dependenciesのオプションは依存関係のあるモジュールをpackage.xmlexample_interfacesに追記してくれる。

  • $ cd ~/colcon_ws/src
  • $ ros2 pkg create --build-type ament_python --node-name simple_server  simple_service --dependencies rclpy  turtlesim std_msgs  

ソースコードを書く前にmy_serviceパッケージをビルドしておく。

  • $ cd ~/colcon_ws
  • $  colcon build --symlink-install

2.  srvの定義確認

この例ではturtlesimモジュールを使っており、リクエストとレスポンスのデータ型を定義しているsrvファイル(/opt/ros/foxy/share/turtlesim/srv/Spawn.srv)を次に示す。—の上4行がクライアントからのリクエスト、下1行がサーバーのレスポンスのデータ型を表す。float32は32ビットのfloat型、stringは文字型である。この他にint64(64ビット整数型)、float64(64ビット浮動小数点型)などもある。ここで、リクエストの(x, y, theta)は亀の位置と向き、nameは名前(空文字の場合は一意の名前をつけてくれる)、レスポンスの名前は亀の名前である。

float32 x
float32 y
float32 theta
string name # Optional.  A unique name will be created and returned if this is empty
---
string name

3.サーバーノードの作成

では、依頼された仕事を処理するサーバープログラムを作ります。次のプログラムをgeditなどを使いsimple_server.pyというファイル名を付けて~/colcon_ws/src/simple_service/simple_service/simple_server.pyとして保存する。

# ファイル名 simple_server.py
import                                                        # ROS2のPythonモジュールをインポート
from turtlesim.srv import Spawn  # turtlesim.srvモジュールからSpawnクラスをインポート
from rclpy.node import Node         # rclpy.nodeモジュールからNodeクラスをインポート

class SimpleService(Node):
""" サーバークラス。クライアンからリクエストされた情報を端末に表示し、名前をリスポンスするサ
"""
    def __init__(self):
        """コンストラクタ。ノード名はsimple_server。サービスの生成。
        super().__init__('simple_server') # スーパークラスNodeのコンストラクタを呼び出してノード名をつける
        self.srv = self.create_service(Spawn, 'spawn', self.spawn_callback) # (型名、サービス名、コールバック関数)
 
    def spawn_callback(self, request, response):
        """コールバック関数。リクエストデータを受け取り、nameが空文字の場合は"kame"という名前をレスポンスとして送り返す
        if request.name == '':
            response.name = 'kame'
        else:
            response.name = request.name
                     
        self.get_logger().info('Request:x=%f, y=%f, theta=%f, name=%s\nResponse:name=%s' % (request.x, request.y, request.theta, request.name, response.name))  # 端末にリクエストとレスポンスデータを表示

        return response


def main(args=None):
    rclpy.init(args=args)                                # rclpyモジュールの初期化
    simple_service = SimpleService()     # ノードの作成
    rclpy.spin(simple_service)                   # コールバック関数の呼び出し
    rclpy.shutdown()                                      # rclpyモジュールの終了処理



if __name__ == '__main__':
    main()

ソースコードにコメントを掲載していますが、必要があれば補足説明します。

4.クライアントノードの作成
次に仕事を依頼するのクライアントのソースコートを作成する。以下のソースコードをsimple_client.pyという名前で~/colcon_ws/src/simple_service/simple_service/simple_client.pyとして保存する。

# ファイル名 simple_client.py
import sys # 端末から入力引数を受け取るために必要
from turtlesim.srv import Spawn
import rclpy
from rclpy.node import Node


class SimpleClient(Node):
"""クライアントクラス。端末から入力されたリクエストデータをサーバーへ送る。
"""
    def __init__(self):
    """コンストラクタ。サーバーと同じ型名とサービス名を持つクライアントの生成。
               型名とサービス名が同じでなければサーバーと通信できない。
    """
        super().__init__('simple_client')
        self.cli = self.create_client(Spawn, 'spawn') # クライアントの生成(型名、サービス名)
        while not self.cli.wait_for_service(timeout_sec=1.0): # 1秒に1回サービスが利用できるかチェック
            self.get_logger().info('service not available, waiting again...')
        self.req = Spawn.Request() # リクエストインスタンスの生成。これにリクエストデータが格納される。

    def send_request(self):
        """端末から入力された引数が順番にリクエストインスタントのx, y, theta, nameに代入される。
        """
        self.req.x           = float(sys.argv[1])     #  亀の位置x座標
        self.req.y           = float(sys.argv[2])     #  亀の位置y座標
        self.req.theta   = float(sys.argv[3])    #  亀の向き[rad]        
        self.req.name  = str(sys.argv[4])        #  亀の名前
        self.future         = self.cli.call_async(self.req) # サービスをリクエストして、結果を非同期的に取得する


def main(args=None):
    rclpy.init(args=args)
    simple_client = SimpleClient()     #  クライアンとオブジェクトの生成  
    simple_client.send_request()       # リクエストを送る

    while rclpy.ok():
        """  Futureが実行されているときは、サーバーからのレスポンスをチェックし、レスポンスがあったらその内容を端末に表示する。
        rclpy.spin_once(simple_client) # コールバック関数を1回だけ呼び出す
        if simple_client.future.done():  #  Futureがキャンセルされるか、結果を得るたらfuture.done()がTrueになる。
            try:
                response = simple_client.future.result() # サーバーから非同期的に送られてきたレスポンス
            except Exception as e:                                         #  エラー時の処理
                simple_client.get_logger().info(
                    'Service call failed %r' % (e,))
            else:  #  エラーでないときは、端末にレスポンスである亀の名前を表示する
                simple_client.get_logger().info('Response:name=%s' % response.name)
            break

    simple_client.destroy_node()
    rclpy.shutdown()


if __name__ == '__main__':
    main()

このプログラムは非同期通信のプログラムで、ROS2ではその実装にFutureというPythonのオブジェクトが広く使われている。Futureオブジェクトについては以下を参照して欲しい。

5.  package.xmlの編集

パッケージを作成するときに--dependenciesのオプションを加えて依存関係のあるモジュールを指定したのでpackage.xmlを編集しなくてもビルドできる。6行目のdescription、7行目のmaintainer、8行目のlicenseを適宜変更する。

6.  setup.pyの編集

package.xmlで変更したmaintainer(16行)、maintainer_email(17行)、description(18行)、license(19行)と同じにする。パッケージを作成するときにノードsimple_serverも作成したので、エントリーポイントは23行目のように既に設定されている。新しく作成したsimple_clientノードのエントリーポイントは作成されていないので、23行目の最後に, (カンマ)を挿入し、24行目のように設定する(追加部分は赤文字)。

  • ‘simple_server = simple_service.simple_server:main’,
  • ‘simple_client = simple_service.simple_client:main’


7. ビルド

次のコマンドでパッケージを指定してビルドする。

  • $ cd ~/colcon_ws
  • $ colcon build --symlink-install 

8.実行

(1)  turtlesimの起動

端末を開き、次のコマンドでturtlesimを起動する。下図のようにturtlesimのウインドウが表示される。

  • $ ros2 run turtlesim turtlesim_node

(2) サーバーの起動

次の端末を開き、次のコマンドでbyobuを起動して、Shift-F2キーを押して窓を上下に分割する。その後、上の窓でサーバーを起動する。

  • $ byobu
  • $ source ~/colcon_ws/install/setup.bash
  • $ ros2 run simple_service simple_serve

(3)  クライアントの起動

サーバーを起動した端末の下の窓で、次のコマンドでクライアントを実行する。

  • $ source ~/colcon_ws/install/setup.bash
  • $ ros2 run simple_service simple_client  10  20  3.14  ''

クライアントはキーボードから亀の位置と姿勢、名前(この例は空文字)をサーバーへリクエストする。この場合は空文字を送ったので、サーバーからのリスポンスは亀の名前’kame’となる。亀の名前をつけてリクエストするとその名前がレスポンスされる。

また、TurtleSimのウインドウにクライアントを実行するたびに亀が現れる。

 

成功したら終わり。うまく動かない場合は、打ち間違えや手順に間違いがないか確認し、再度実行しましょう。お疲れ様!

ホームワーク

  1.  コマンドでもサービスを実行できます。以下のコマンドを実行して動作を確認してみよう。
    • $ ros2 service call /spawn turtlesim/srv/Spawn “{x: 2, y: 2, theta: 0.2, name: ”}”
  2.    以下のROS2チュートリアルを読んで、ROS2のサービスに関する理解を深めよう。
  3.    [ROS2演習2-2021:亀で遊ぼう!]ではspawnサービスの他に、killサービス、resetサービス、set_penサービス、clearサービスなどがありました。どれか一つを選び、そのサービスをリクエストするクライアントパッケージを作成して、動作を確認してください。

終わり

 


ASUS TUF DASH F15に変えてみた

$
0
0

メインノートPCをRAZER Blade 15 (2018)からASUS TUF DASH F15に変えた。ソフトウェア設定などの備忘録。

背 景

  • メインで使用していたRAZER Blade 15のバッテリーが膨れて筐体が変形し、充電もできなくなった。電源のないところでもノートPCは使う場合もあるので、急遽代替えのノートPCを探した。
    また、RAZERは購入してから3年経過し、数回故障したことがありそろそろ買い替え時期にも来ている。

選定理由

  • 深層学習の学習や推論をするためにNVIDIA GPUは必須。できるだけ高性能の方が学習時間や推論時間が短くなるのでRTX 3070を搭載していることが第1条件。これにより選択肢がとても狭まる。
  • RAZERは数回故障して仕事に支障が出たので堅牢性のあるノートPC。選定したASUS TUF DASH F15は米国国防総省が定める軍事規格のMIL規格MIL-STD-810H準拠のテスト(Method 516.8, Procedre VI)をクリアした製品。
  • 重量が2.1kgで、持ち歩ける範囲の重量。
  • 価格も約20万円で、このスペックのノートPCではとてもリーズナブル
  • 比較的簡単にSSD増設、メモリの換装も可能。ただし、自己責任。

いまいちのところ

  • RAZERよりかっこ悪い
  • 奥行きがRAZERより15mmも長い
  • カメラが内蔵されていない
  • ASUS Storeの対応が悪く遅い。結局、Amazonで購入した。

スペック

  • OS: Windows 10 Home 64bit
  • CPU: Intel Core i7-11370H
  • GPU: NVIDIA GeForce RTX 3070 (Memory 8GB)
  • Display: 15.6inch, Full HD, 240Hz
  • Memory: 16GB
  • Storage: SSD 1TB
  • Size: Width 360mm x Length 252mm x Height 19.9~20.9
  • Weight: 2.1kg

ハードウェアの増設

  • SSD Samsung 970 EVO Plus (2TB)
  • 増設方法:この動画はわかりやすい。

 

ソフトウェア

  • 自分で作成したファイルはすべてクラウドにあるので引っ越しする必要はないので、アプリのみインストールした。
  • インストールしたアプリ(アルファベット順)
    • Box desktop
    • ELSA GPU Optimizer
    • ESET Endpoint AntiVirus
    • FortiClient
    • Folding@home
    • Garmin Express
    • Google Chrome
    • Microsoft Office Professional Plus 2019
    • Slack
    • SnapCrab for Windows

終わり

 

 

Ubuntu20.04:インストールと設定

$
0
0

Ubuntu20.04をASUS TUF DASH F15にインストールと設定したのでその備忘録。ここでは、増設したSSD(Samsung 970 EVO Plus  2TB)にインストールした。VOYAGER GE 20.04を当初インストールしたが4Kディスプレイを自動認識しないのでスタンダードなUbuntu20.04にした。作業時間は1時間程度だった。

注意:以下の作業でWindowsが消えたり、起動しなくなったり、ファイルが消えたりしても、私は一切責任を取れません。重要なファイルはバックアップを取ってから、自己責任で作業をしてください。

準 備

  • Windows PC: 1台
    • BIOSモード:UEFI
      • BIOSモードの確認は検索バーに[msinfo32]と入力してEnterキーを押すと[システム情報]が開き確認できる。BIOSモードがLegacy BIOSのときは、Googleで調べてUEFIに変更してください。
  • インストール用のUSBメモリ(以降、インストールUSBと表記 ):1個
    • Ubunut20.04のイメージは約2.7GBなので4GBもあれば十分。USB2.0でもOK。
    • この例ではTOSHIBA USB2.0メモリ TNU-A016B (8GB)を使用した。
  • 作業を間違えるとWindowsが丸ごと消えるので、重要なファイルは必ずバックアップを取っておく。

作業の流れ

  • 作業1:Ubuntu 20.04 LTSイメージのダウンロード(所用時間:約5分)
  • 作業2:Rufus (USBメモリ等にイメージを書き込むソフト)でUbuntuイメージをインストールUSBに書き込む(所用時間:約10分)
  • 作業3:インストールUSBでPCを起動して、Ubuntu USBにUbuntuをインストールする。(所用時間:約30分~1時間)
  • 作業4:動作確認(所用時間:約3分)
  • 注:所用時間は目安でありネットワーク環境によって大きく変わります。

作業1:Ubuntu 20.04 LTSイメージのダウンロード

作業2:RufusでUbuntuイメージをインストールUSBに書き込む

  • 以下のサイトからRufus 3.13 Portableをダウンロードして、Ubuntuイメージと同じ場所に保存する。探すのが面倒な場合はここをクリックする。
  • インストールUSBをPCに差し込む。
  • ダウンロードしたRufusはポータブル版なのでインストール不要。rufus-3.13p.exeをダブルクリックすると起動する。
  • 起動したら下図のように設定してから、右下の[スタート]をクリックする。途中でいくつか聞かれるがデフォルトのままでOK。Ubuntuのイメージの書き込みが終わったら[状態]の[準備完了]が全て緑色になるので[閉じる]をクリックして終了する。
    • デバイス:USBメモリを選択する。
    • ブートの種類:[選択]をクリックして、ダウンロードしたファイルを選択し、[開く]をクリックすると、ブートの種類が下図のように[Ubuntu-20.04.2.0-desktop-amd64.iso]となる。
    • その他の項目は以下のようにデフォルトのままでOK。

作業3:インストールUSBでPCを起動して、Ubuntu USBにUbuntuをインストールする。ネットワークに接続された環境で行う。

  • Ubuntu USBとイメージを書き込んだインストールUSBをPCに差し込み、PCを再起動する。
  • 再起動したらすぐBIOS画面(私のRazerではF2、機種で違うので調べる)にして、USBからブートできるように設定する。

  • [GNU GRUB]の画面になる。1番上の[Ubuntu]が選択されていることを確認してEnterキーを押す。

 

  • [Welcome]の言語選択の画面になるので、一番下の[日本語]を選ぶと以降日本語でインストール作業ができる。日本語を選択して[Ubuntuをインストール]をクリックする。

  • [キーボードレイアウト]の画面になるので、自分のキーボードが選択されていることを確認して、[続ける]をクリックする。

 

  • 有線LANを接続していないと、[無線]の画面になるのでwifi-fiを設定する。接続するネットワークを選択し、パスワードを入れる。
  • [アップデートと他のソフトウェア」の画面になるので、以下のように設定して[続ける]をクリックする。

  • [インストールの種類]の画面になる。これからの作業を間違えるとWindowsが消えてしまうので、これから細心の注意を払う。インストールの種類は[それ以外]を選択して[続ける]をクリック。

  • インストールしたいSSDに割り当てられている領域を選択する。サイズを見るとわかる。この例では、1.82TiBを割り当てられている/dev/nvme0n1。
  • USBにはUbuntuのブートローダがインストールされるEFIシステムパーティションとUbuntuがインストールされるルートパーティションを作る。まず、EFIシステムパーティション領域を作成する。上図の[空き領域]になった箇所を選んで、左下の[+]をクリックすると次のウインドウが開くので、次のように設定して[OK]をクリックする。
    • サイズ:200MB
    • 新しいパーティションのタイプ:基本パーティション
    • 利用方法:EFIシステムパーティション

  • 次に、ルートパーティションを作る。同様にして空き領域を選び、左下の[+]をクリックしてパーティションを作成する。今回、増設したSSDは2TBあるので、その半分1TBをルートパーティションに割り当てた。残りはWindowsでも使うかもしれないので空き領域のままとした。の全てのサイズをルートパーティションに割り当てる。マウントポイントを/にすることを忘れないように。[OK]をクリックする。
    • 新しいパーティションのタイプ:基本パーティション
    • 利用方法:ext4ジャーナリングファイルシステム
    • マウントポイント:/
  • 最終的な/dev/nvme0n1の構成は以下のようになる。Swapに関してはUbuntu20.04ではディスクの空き容量の5%または2GBの小さい方がswapfileとして自動で作られる。
  • 次にUbuntuを起動するブートローダをインストールするデバイスを指定する。SSDから起動するので、SSDでEFIシステムパーエィションを設定したデバイスを選ぶ。この作業も最新の注意を払う。
  • [ディスクに書き込みますか?]が出てくるので、初期化されるパーティションに間違いがないか確認する。間違えるとWindowsが消えたり、起動しなくなるのでよく確認すること。問題がなければ[続ける]をクリックする。
  • [どこに住んでいますか?]画面になるので、地方に住んでいても[Tokyo]のまま[続ける]をクリックする。

  • [あなたの情報を入力してください]画面になるので、必要な情報を入力して[続ける]をクリックする。
  • [Ubuntuへようこそ]画面になり、システムがUSBメモリにインストールされる。終わるまで、7分程度かかった。
  • [インストールが終了しました]画面になる。[今すぐ再起動する]をクリックして再起動する。

  • インストールUSB(下図ではinstallation medium)を抜いてからEnterキーを押すと再起動する。

作業4:動作確認

  • 再起動するとGRUBの画面になるので10秒待つと自動起動する。GRUBはGNUプロジェクトで開発されているブートローダ。下図の場合、Windowsを起動したい場合は[Windows Boot Manager]を下矢印キーで選択してEnterキーを押すとWindowsが立ち上がる。もし、GRUBの画面が出ずにWindowsが立ち上がったらBIOSでUbuntu USBからブートするように設定する。

  • 以下の画面になれば成功。パスワードを入れてログインしよう!

少し幸せになる設定

  • 私がUbunutuをインストールするときによく使う設定等を紹介しよう!
  • 設定
    • ホームディレクトリのフォルダ名を日本語から英語に変更する。Linuxはコマンドを打つ場合が多いので日本語のディレクトリは何かと困る。以下のコマンドを端末で実行する。端末は、下図の左下隅にある9個の点アイコン[アプリケーションを表示する]をクリックすると最上部に現れる[検索窓]に[terminal]と入力すると見つけることができる。なお、以下のコマンドで$はプロンプトなので打ち込まない。
      •  $ LANG=C xdg-user-dirs-gtk-update
        • Enterキーを押すとウインドウが開くので、”Don’t ask me this again”にチェックを入れて、[Update Names]をクリックする。
    • CAPS LOCKとCTRLキーの入れ替える。CTRLキーを使う機会が多いので入れ替える。
      • Tweak toolをインストールする。
        • $ sudo apt install gnome-tweak-tool
      • gnome-tweaksを起動する。
        • $ gnome-tweaks
      • [キーボードとマウス]→[キーボード]→[追加のレイアウトオプション]→[Ctrol position]の[□CtrlとCaps Lockを入れ替える]に下図のようにチェックを入れる。再起動すると有効になる。

    • 時間をローカルタイムにする
      • 同じコンピュータでWindowsとLinuxを使うとWindowsの時間帯が世界標準時になり-9時間ずれるので、Linuxの時間を次のコマンドでローカルタイムにする。
        • $ sudo timedatectl set-local-rtc true
    • swapファイルの設定
      • TUF DASH F15はメモリを16GB搭載しているので、swapファイル2GBから32GBに拡大する。
      • まず、swapファイルを確認しよう。
        • $ swapon -s

        • /swapfileに2GB割り当てられていることがわかる。
      • swapファイルのサイズを変更するためにswapを無効化する。
        • $ sudo swapoff -a
      • swapファイルのサイズを変更する。次のコマンドを実行するとswapファイルのサイズが32GiBになっていることがわかる。ここで、GBは10の累乗なので1000倍毎、GiBは2の累乗で1024倍毎に単位が変わる。
        • $ sudo dd if=/dev/zero of=/swapfile bs=1G count=32

      • /swapfileをswapファイルにする。
        • sudo mkswap /swapfile
      • swapファイルを有効化する。
        • sudo swapon /swapfile
      • 再起動して、swapが割り当てられているか次のコマンドで確認する。Swapに32.0G割り当てられいたら成功。
        • free -h

  •  アプリのインストール
    • 端末を開き、以下のコマンドを実行してインストールする。
      • $ wget https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb
      • $ sudo apt install ./google-chrome-stable_current_amd64.deb
      • $ sudo apt install git emacs vim htop tmux byobu grub-customizer

終わり

お疲れ様!

 

VSCodeの設定

$
0
0

Visual Stdudio CodeをUbuntu20.04にインストール・設定したので備忘録

  • インストール
  • 設定
    • 拡張機能
      • Awesome Emacs Keymap:emacsのキーバインディング
      • GitHub Theme:配色テーマ
      • Japanese Language Pack for Visual Studio Code:日本語化
      • Prettier:コード整形
      • Python:Python言語サポート
      • ZenKaku:全角スペースをグレーで表示
    • settings.json

以上

ROS2演習7-2021:Turtlebot3をプログラムで動かそう

$
0
0

この記事は私が金沢工業大学ロボティクス学科で担当している2020年度後学期に担当したロボットプログラミングⅡをROS2用に変更したものです。今回は、ROS2演習4-2021の知識を使いTurtlebot3をPythonプログラムで動かします。ソースコードは完成していますが、この記事の説明やハンズオンは作成中です。

ソースコード

今回使用するソースコードです。コード中にコメントを多く入れたのでそれを読むと理解できると思います。必要があれば説明を補足します。

import rclpy  # ROS2のPythonモジュールのインポート 
import time   # timeモジュールのインポート                                                                        
import math   # 数学関数モジュールのインポート                                                                    
import numpy as np # numpyモジュールを別名npをつけてインポート                                                    
from rclpy.node import Node # rclpy.nodeモジュールからNodeクラスをインポート                                      
from std_msgs.msg import String # トピック通信に使うStringメッセージ型をインポート                                
from geometry_msgs.msg import Twist # トピック通信に使うTwistメッセージ型をインポート                             
from nav_msgs.msg import Odometry # nav_msgs.msgモジュールからOdometryクラスをインポート                          
                                                                                                                  
                                                                                                                  
class Pose:                                                                                                       
    """"姿勢のクラス    
        位置(x, y)、向き(yaw)                                                                               
    """                                                                                                           
    def __init__(self, x = 0.0, y = 0.0, yaw = 0.0):                                                              
        self.x = x                                                                                                
        self.y = y                                                                                                
        self.yaw = yaw                                                                                            
                                                                                                                  
    def set(self, x, y, yaw):                                                                                     
        self.x = x                                                                                                
        self.y = y                                                                                                
        self.yaw = yaw                                                                                            
                                                                                                                  
    def get(self):                                                                                                
        return self.x, self.y, self.yaw                                                                           
                                                                                                                  
class MyRobot(Node):                                                                                              
    """MyRobotクラス。ロボットに速度指令cmd_velをパブリッシュしたり、
       odomトピックをサブスクライブして姿勢を取得するクラス。           
       Node: MyRobotクラスが継承するクラス                                                                   
    """                                                                                                           
                                                                                                                  
    def __init__(self):                                                                                           
        """コンストラクタ。パブリッシャーとタイマーを生成する。                                                   
        """                                                                                                       
        # Nodeクラスのコンストラクタを呼び出し、'my_robot'というノード名をつける。                                
        super().__init__('my_robot')                                                                              
                                                                                                                  
        # パブリッシャーの生成。create_publisherの1番目の引数はトピック通信に使うメッセージ型。                   
        # Twist型は速度指令値を通信するのに使われる。2番目の引数'cmd_vel'はトピック名。                           
        # 3番目の引数はキューのサイズ。キューサイズはQOS(quality of service)の設定に使われる。                    
        # サブスクライバーがデータを何らかの理由で受信できないときのキューサイズの上限となる。                    
        self.pub = self.create_publisher(Twist,'cmd_vel', 10)                                                     
                                                                                                                  
        # サブスクライバーの生成。create_subscriptionの1番目の引数Twistはトピック通信に使うメッセージ型。         
        # Twist型は速度指令値を通信するのに使われる。2番目の引数'cmd_vel'はトピック名。                           
        # 3番目の引数はコールバック関数。 4番目の引数はキューのサイズ。                                           
        self.sub = self.create_subscription(Odometry,'odom', self.odom_callback, 10)                              
                                                                                                                  
        # Twistメッセージ型オブジェクトの生成。メンバーにdVector3型の並進速度成分linear、                         
        # 角速度成分angularを持つ。                                                                               
        self.vel = Twist()                                                                                        
        print("*** my_robot node ***")                                                                            
        print("Input f, b, r, l  key, then press Enter key.")                                                     
                                                                                                                  
        self.state = 0                                                                                            
        self.odom  = Odometry()                                                                                   
        self.pose  = Pose()                                                                                       
                                                                                                                  
                                                                                                                  
    def euler_from_quaternion(self,quaternion):                                                                   
        """クオータニオンからオイラー角を計算する関数                                                        
        Converts quaternion (w in last place) to euler roll, pitch, yaw                                           
        quaternion = [x, y, z, w]                                                                                 
        Bellow should be replaced when porting for ROS 2 Python tf_conversions is done.                           
        """                                                                                                      
        x = quaternion.x                                                                                          
        y = quaternion.y                                                                                          
        z = quaternion.z                                                                                          
        w = quaternion.w                                                                                          
                                                                                                                  
        sinr_cosp = 2 * (w * x + y * z)                                                                           
        cosr_cosp = 1 - 2 * (x * x + y * y)                                                                       
        roll      = np.arctan2(sinr_cosp, cosr_cosp)                                                              
                                                                                                                  
        sinp  = 2 * (w * y - z * x)                                                                               
        pitch = np.arcsin(sinp)                                                                                   
                                                                                                                  
        siny_cosp = 2 * (w * z + x * y)                                                                           
        cosy_cosp = 1 - 2 * (y * y + z * z)                                                                       
        yaw = np.arctan2(siny_cosp, cosy_cosp)                                                                    
                                                                                                                  
        return roll, pitch, yaw  

   def odom_callback(self, odom):                                                                                
        """サブスクライバーのコールバック関数。端末に並進と角速度を表示する。                                     
        """                                                                                                       
        self.get_logger().info("Pose: x=%f y=%f" % (odom.pose.pose.position.x,odom.pose.pose.position.y))         
        self.get_logger().info("Vel:  Linear=%f angular=%f" % (odom.twist.twist.linear.x,odom.twist.twist.angular\
.z))                                                                                                              
        x = odom.pose.pose.position.x                                                                             
        y = odom.pose.pose.position.y                                                                             
                                                                                                                  
        roll, pitch, yaw = self.euler_from_quaternion(odom.pose.pose.orientation)                                 
                                                                                                                  
        self.pose.set(x, y, yaw)                                                                                  
        print("callback pose =", x, y, yaw)                                                                       
                                                                                                                  
                                                                                                                  
    def move(self, linear, angular = 0.0):                                                                        
        """移動関数                                                                                               
           linear: 並進速度, angular:角速度. 省略されたときは0.0を代入                                            
        """                                                                                                       
        self.vel.linear.x = linear                                                                                
        self.vel.angular.z = angular                                                                              
        self.pub.publish(self.vel)                                                                                
                                                                                                                  
                                                                                                                  
    def distance(self, pose1, pose0):                                                                             
        """距離関数                                                                                               
           pose1: 現在の姿勢(x, y), pose0:スタートの姿勢                                                          
        """                                                                                                       
        d = math.sqrt((pose1.x - pose0.x) * (pose1.x - pose0.x) \                                                 
            + (pose1.y - pose0.y) * (pose1.y - pose0.y))                                                          
        print("d=",d)                                                                                             
        return d                                                                                                  
                                                                                                                  
                                                                                                                  
    def print(self, sentence):                                                                                    
        """ 表示                                                                                                  
            sentence: 文字列                                                                                      
        """                                                                                                       
        self.get_logger().info(sentence)                                                                          
                                                                                                                  
                                                                                                                  
def main(args=None):                                                                                              
    rclpy.init(args=args) # rclpyモジュールの初期化                                                               
    my_robot = MyRobot()  # ノードの作成
                                                                                  
    v = Twist()                                                                 
    t = 5.0 # time [s]                                                          
    d = 1.0 # distance [m]                                                      
                                                                                
    while rclpy.ok():                                                           
        if my_robot.state == 0:        # 開始状態                               
            my_robot.state = 1                                                  
            start_time = time.time()                                            
            my_robot.print("State 1")                                           
        elif my_robot.state == 1:      # 前進状態。t[s]間前進。                 
            my_robot.move(0.2)                                                  
            if time.time() - start_time > t:                                    
                my_robot.state = 2                                              
                start_time = time.time()                                        
                my_robot.print("State 2")                                       
        elif my_robot.state == 2:      # 停止状態。t[s]間停止。                 
            my_robot.move(0.0)                                                  
            if time.time() - start_time > t:                                    
                my_robot.state = 3                                              
                start_pose = Pose()                                             
                start_pose.x, start_pose.y, start_pose.ya = my_robot.pose.get() 
                my_robot.print("State 3")                                       
        elif my_robot.state == 3:      # 後進状態。d[m]後進。                   
            my_robot.move(-0.2)                                                 
            print("start=", start_pose.x, start_pose.y)                         
            if my_robot.distance(my_robot.pose, start_pose) > d:                
                my_robot.state = 4                                              
                my_robot.print("State 4")                                       
        else:                          # 終了状態。停止してノードを破壊         
            my_robot.move(0.0)                                                  
            my_robot.print("End")                                               
            my_robot.destroy_node()                                             
                                                                                
        rclpy.spin_once(my_robot)                                               
                                                                                
                                                                                
    rclpy.shutdown()        # rclpyモジュールの終了処理                         
                                                                                
                                                                               
                                                                                
if __name__ == '__main__':                                                      
    main()                          

ハンズオン

  • パッケージの作成
    • ここでは、パッケージ名とノード名を同じmy_robotにする。
      • $ cd ~/colcon_ws/src
      • $ ros2 pkg create --build-type ament_python --node-name my_robot  my_robot
  • ソースコードの作成
    • 好きなエディタで次のファイルを開き、上のコードを上書き保存する。
      •  ~/colcon_ws/src/my_robot/my_robot/my_robot.py
  • setup.pyとpackage.xmlの変更
    • 以前の演習を参考に必要に応じてsetup.pyとpackage.xmlを変更する。
  • ビルド
    • $ cd ~/colcon_ws
    • $ colcon build --symlink-install
      • なお、symlink-installはPython言語の場合にソースコードを変えても再ビルドが必要なくなる便利なオプション。
  • 実 行
    • 端末を開き、byobuを実行する。
      • $ byobu
    • Shift-F2で端末を分割し、上の窓で次のコマンドを実行する。
      • $ export TURTLEBOT3_MODEL=burger
      • $ ros2 launch turtlebot3_gazebo empty_world.launch.py
    • 下の窓で次のコマンドを実行する。
      • $ ros2 run my_robot my_robot
    • 実行すると速度0.2[m/s]で5秒間直進し、3秒停止、速度-0.2[m/s]で1[m]直進して停止する。つまり、スタート地点に戻る。

ホームワーク

  1. ソースコードのeuler_from_quaternion関数はクオータニオンからオイラー角への変換する関数です。クオータニオンとオイラー角を調べて、この関数の処理を理解しよう。
  2. main関数は開始状態から前進状態→停止状態→後進状態→終了状態へと状態遷移に基づくコードになっており、whileループの最後に、毎回spin_once()関数でコールバック関数を呼び出しています。前進状態は、状態1になったときの時間から計測してt[s]経過したら、次の状態2(停止)に遷移することで実現しています。このような処理ではなく、t[s]経過したら停止するmove_second(t)関数を作ってください。
  3. 作成中

 

終わり。お疲れ様!

Webots入門講座1:ブレイクの予感とデモの鑑賞

$
0
0

ブレイクの予感

最近,Webotsというロボットシミュレータを良く耳にしませんか?ロボカップジュニア世界大会がオンライン開催になり,サッカーチャレンジをはじめとする複数のリーグでWebotsを使った競技が開催されます.また,知能ホームロボティクス入門講習会2021でも,Windows版ROS2ではGazeboではなくWebotsが使われました.ブレイクの予感がします.

Webotsとは何でしょう?それは,Webotsはオープンソースでマルチプラットフォームのロボットシミュレータです.Webotsは1996年にスイス連邦工科大学のOliver Michel博士が開発し,1998年にCyberbotics社がライセンスを取得し,2018年からはオープンソース(Apache2ライセンス)になりました.

主な特徴は次のとおりです.

  • オープンソース:Apache2
  • マルチプラットフォーム:Windows, Linux, Mac OS
  • 多くのプログラミング言語に対応:C, C++, Python, Java, MATLAB, ROS
  • 高速プロトタイピング:多くのロボットモデル,センサ,アクチュエータ,物体,素材がある.3Dモデルフォーマット,URDFをインポート可能であり,ロボットのプロトタイプを高速に作ることができる.
  • 定評のある物理エンジン:Open Dynamics Engine (ODE)のフォーク(派生).
  • ドキュメントが豊富:チュートリアル,ユーザガイド,リファレンスマニュアル,プログラムサンプルなどが完備

インストール

では,シミュレータで遊ぶためにさっそくインストールしましょう!

  • ダウンロード
    • Cyberbotics社のダウンロードサイトからセットアップファイルをダウンロードする.ファイルのサイズは1.63GBですが,ダウンロードが終わると2.73GBになります.
    • ダウンロードしたセットアップファイル(webots-R2021a_setup.exe)にマウスのカーソルを合わせて,管理者権限で起動する.
    • Select Setup Install Mode窓が開くので,[Install for all users]をクリックする.私の環境では,[-> Install for me only (recommmended)]ではWebotsを起動したときに不具合があった.
    • Select Destination Location窓が開くのインストール先を変える.特にこだわりがなければ,そのままで良いので[Netx >]をクリック.
    • Select Star Menu Folder窓になる.デフォルトではスタートメニューフォルダにショートカットを作成してくれる.違うフォルダに作成したい場合は[Browse…]をクリックして選択する.ここでは,そのまま,[Next >]をクリックする.
    • Ready to Install窓になるので,[Install]をクリックしてインストールを始める.
    • Installing窓になる.インストールはすぐ終わる.私の環境では2分ぐらいで終わった.
    • インストールが終わると次の窓になる.[Finish]を押すと,Webotsが起動する.

デモの鑑賞

  • インストールして初回はWelcom to Webots R2021aというウェルカムメッセージ窓が開く。後で設定を変更できるので、このまま一番下の[Start Webots with the selected theme]をクリックしよう。
  • Guided Tour窓が開く。ここでWebotsを紹介してくれる。ここでお勧めなのは自動ツアー。左下にAutoのチェックボックスがあるので、チェックを入れて[Next]をクリックする。そうすると63もあるデモを自動で紹介してくれる。十二分に鑑賞を楽しめます!
  • トップバッターはSpot君。この後、挨拶をしますよ。
  • Annimated skin:リッチなスキンをもったサラマンダーロボット。水に浮くダックを狙っているのか!?
  • サッカーをするRobotis OP2。手拍子を要求。
  • あの産業ロボットも登場
  • この他に,DJI Drone, PR2,Create, Pioneerなど多数のロボットが登場します.
  • 十分楽しんだと思うので,次は、さっそく簡単なプログラムを組んでロボットを動かしましょう!

終わり

Anaconda3のインストール(Windows)

$
0
0

Pythonに加えて機械学習やデータサイエンス関連のライブラリをたくさん含むAnacondaをインストールを紹介します.なお,Anacondaは商用利用の場合は有償です.

ここでは,個人,学生,研究者向けのAnaconda Individual Editionを次のAnacondaサイトからダウンロードします.

  • Anaconda Individual Edition
  • Windows:Python 3.8 64-Bit Graphical Installer (477MB)をクリックしてダウンロードする.
  • ダウンロードしたファイルをダブルクリックして起動する.次のWelcome窓が開くので[Next>]をクリック.
  • License Agreement窓になるので,ライセンスを読んで同意する(同意しないと使えない).[I  Agree]をクリックする.
  • Select Installation Type窓になる.デフォルトは”Just Me (recommended)”になっているので,そのまま[Next >]をクリックする.
  • Choose Install Location窓になる.インストール先はデフォルトだとCドライブのユーザ下に置かれる.必要があればインストール先を変更する.なければ,そのまま,[Next>]をクリックする.なお,インストールには2.9GBの空き容量が必要なので,空き容量が少ない場合は注意.
  • Advanced Installation Options窓になる.上のオプションで”Add Anaconda3 to my PATH environment variable”とあるが,これにチェックを入れるとアンインストールや再インストールでいろいろ問題が起きるので,このまま[Install]をクリックする.
  • インストールが始まる.僕の環境だと2分ぐらいですく終わった.
  • インストールが終わると,”Completed”と出るので,[Next >]をクリックする.
  • Anaconda3 2021.05(64-bit)窓になるので[Next>]をクリックする.
  • Completing Anaconda3窓になるので,[Finish]をクリックする.
  • 上で,Anaconda Individual Edition TutorialとGetting Started with Anacondaにチェックが入っていたので,次のページが開く.
  • インストールはこれで終了.必要に応じて”Individual Edition Tutorial”や”Quick Start Guide”を読んで,使い方を覚える.

終わり

Webots入門講座2:プログラミングしよう!(Python)

$
0
0

ブレイクの予感がするWebots入門講座の2回目です.さっそく,Pythonを使ってロボットを動かしてみましょう.

環 境

  • Windows 10
  • Anaconda3 (Python 3.8)
  • Webots R2021a

Webotsの日本語化

  • Webotsはオフィシャルに日本に対応しているので,日本語にしましょう.
  • Webotsを起動する.
  • 窓の上部にあるメニューバーの[Wizard]→[Preferences]→[General]のLanguage:を”Japanese-日本語”にして[OK]をクリックする.メニューバーの[File]→[Exit]でWebotsを終了させる.Webotsを再起動すると日本語表示になる.

 

Anacondaのインストール

  • Pythonに加えて機械学習やデータサイエンス関連のライブラリをたくさん含むAnacondaを次のリンクの説明に従ってインストールします.Anaconda3やPython3.7, 3.8, または3.9がインストールされている場合はインストールの必要はありません.Anacondaは商用利用の場合は有償です.

ライブラリのインストール

  • WebotsにはコンピュータビジョンライブラリOpenCVを使うデモがあり,OpenCVはよく使うのでインストールする.Windowsのスタートメニューから→anaconda3(64bit)→Anaconda Prompt(anaconda3)を起動する.
  • Anaconda Prompt (anaconda3)で次のコマンドを実行する.
    • pip install opencv-python

Pythonのパス設定

  • PythonがどこにあるかをWebotsに知らせるために,Windowsのシステム環境変数PATHを設定する必要があります.
  • Windowsの下にあるタスクバーの左にある検索窓[ここに入力して検索]に「環境変数」と入力すると下図のように[環境変数を編集]が現れるので,それをクリックする.
  • [環境変数]窓が開くので,Pathをクリックし選択してから,[編集(E)…]をクリックする.
  • [環境変数名の編集]窓になるので,[新規(N)]をクリックする.
  • [参照(B)…]をクリックしてpython.exeがあるフォルダを選択する.選択するとそのフォルダのあるパスが追加される.この例では,Anaconda3をユーザフォルダにインストールしているので,以下のフォルダになる.[OK]をクリックして保存する.
    • C:\Users\ユーザ名\anaconda3
    • 同様にして次の2つのパスも追加して,[OK]を教えて保存する.
      • C:\Users\ユーザ名\anaconda3\Scripts
      • C:\Users\ユーザ名\anaconda3\Library\bin
      • 環境変数をシステムに反映させるために,Windowsを再起動する.

Pythonの動作確認

  • WebotsでPythonが動作するか確認しましょう.
  • Webotsを起動して,メニューバーの[ファイル]→[Open sample world…]を選択すると[Open Sample World]窓が開く.
  • [languages]→[Python]を選択すると下図のような碁盤の目とかわいいロボット3台のワールドが現れる.現れれば成功!現れない場合は,Windowsのシステム環境変数にPythonのパスが正しく設定されていない可能性が高いのでPythonパスの設定作業を確認する.

はじめてのWebotsプログラミング

  • 準 備
    • プロジェクトを格納するフォルダとして”C:\ユーザ\ユーザ名\webots”をエクスプローラで作成する.
  • プロジェクトの作成
    • メニューの[ウィザード]→[新規プロジェクトのディレクトリ…]を選択する.ディレクトリはフォルダのこと.下の窓が開くので[次へ(N)]をクリックする.
    • 「ディレクトリの選択」窓になるのでmy_projectをhello_worldに変更して[次へ(N)]をクリックする.下のdemuraは私のユーザ名なので,自分のユーザ名に変更する.
    • 「World settings」窓になる.ワールドはシミュレータ上の仮想世界になり,ロボットはそのワールドで動作します.ここでは,ワールド名はhello_world.wbtに変更し,一番下の”Add a rectangle arena”にチェックを入れて[次へ(N)]をクリックする.ワールド名の最後のwbtはワールドファイルの拡張子となります.
    • 「結果」窓になるので[完了(F)]をクリックする.
    • 市松模様のボードRectangleArena(四角いアリーナ)が下図のように現れる.
    • 次に,このRectangleArenaの属性を変えてみよう!左欄の上から5番目にあるRectangleArenaをダブルクリックすると展開され属性が現れる.まず,床のサイズを変更しよう.floorSizeをクリックすると,下欄[Selection floorSize (Vector2)]のxとyに2を入力するとサイズが縦横2倍になる.同様にして,floorTileSizeやwallHeightなどを変えて遊んでみよう.変更したらメニューバーの[ファイル]→[ワードファイルを保存]を選択してワールドを保存する.
  • ロボットの追加
    • 次にロボットをアリーナに登場させよう.ロボットはいろいろ用意されているが,ここではソフトバンクのNaoに登場願おう.RectangelArenaをクリックして,その上にある[+]をクリックすると[ノードを追加]窓が開くので,[PROTO nodes (Webots Projects)]→[robots]→[softbank]→[nao]→[Nao (Robot)]を選択して[追加]をクリックする.
    • 下図のようにアリーナの中央にNaoが現れる.次はこのロボットのコントローラを作ります.
  • コントローラの作成
    • ワールドとロボットを作ったので,次はコントローラを作成します.Webotsではコントローラをプログラミングすることでロボットを動かします.メニューバーから[ウィザード]→[新規ロボットのコントローラ…]を選択する.「新規コントローラの作成」窓が開くので[次へ(N)]をクリックする.
    • 「言語選択」窓が開くのでPythonにチェックを入れ,[次へ(N)]をクリックする.
    • 「名前の選択」窓になるので,コントローラの名前を入力する.ここでは”hello_world_controller”にする.[次へ(N)]をクリック.
    • 「結果」窓になるので[完了(F)]をクリックする.
    • テキストエディタが開き,次のようなコントローラの雛形プログラムが自動的に作られる.
    • ここでは,上の雛形コードを下のように変更します.プログラミング言語で定番の初めてのコードといえば,”hello, world”ですね.変更したらエディタの上にあるフロッピーディスクのアイコンをクリックして保存します.
      from controller import Robot 
      
      robot = Robot() 
      
      while robot.step(32) != -1: 
          print("hello, world")
      

 

 

ソースコードを説明します.1行目で controllerモジュールからRobotクラスをインポートし,3行目は Robotクラスのインスタンスを生成します.5行目のrobot.step(32)はシミュレータのタイムステップを表し,1ループで32[ms]シミュレーションを進めるという意味です.この時間を小さくすると計算精度は高くなりますが,シミュレーションは遅くなります.逆に大きくするとシミュレーションは速くなりますが,精度が悪くなり,シミュレータと実世界でのロボットの動きが変わってしまいます.このコントローラはロボットを動かすのではなく,シミュレータが終わるまで,”hello, world”とコンソールに出力し続けるだけです.

  • ロボットへのコントローラ組込み
    • 次にこのコントローラプログラムをロボットに組込みます.組み込まないとプログラムは動作しません.左欄の[Nao]→[controller]を選択し,下の[Selection controller (String)]欄の[選択…]をクリックするとコントローラの一覧が現れるので,その中から先ほど作成した”hello_world_controller”をクリックして組み込みます.ワールドを保存する.
  • 実 行
    • Pythonなのでビルドする必要はありません.プログラムを実行するためには,まず,シミュレーション表示部分の上にある,[reset]ボタンを押して,シミュレーションをリセットして初期化します.次に,[run]ボタンを押すとプログラムが実行され,下欄の[Console – All]に “hello, world”と表示されます.今回のプログラムはコンソールに”hello world”と表示するだけの簡単なものです.次回は車輪型ロボットをプログラムで動かしますのでお楽しみに!なお,表示されない場合は,Pythonのコード(インデントなど)に問題がないか確認してください.

 

終わり


ロボット知能工学特論:第9週 演習

$
0
0

このページは金沢工業大学大学院機械工学専攻ロボット知能工学特論のサポートページです。第9週はファイナルプロジェクトに使用するロボットシミュレータWebotsのインストール,使い方並びに簡単なプログラムの作成演習となります.次のリンクから2つの演習に取り組んでください.

  1. Webots入門講座1:ブレイクの予感とデモの鑑賞
  2. Webots入門講座2:プログラミングしよう!(Python)

終わり

 

サーバー移転のテスト中

$
0
0

いつもdemura.netにアクセスして頂きありがとうございます.現在,使用しているサーバーは503エラーが頻発し大変ご迷惑をおかけしたと思います.この問題を解決するために,2021年6月21日から新しいサーバーで試しに運用しています.今週テストして問題がなければ新サーバーに移転します.引き続き,demura.netをよろしくお願いします.

ロボット知能工学特論:第10週 演習2

$
0
0

 

このページは金沢工業大学大学院機械工学専攻ロボット知能工学特論のサポートページです。第10週はファイナルプロジェクトで使用するワールドCityでロボットカーを動かす簡単なプログラム演習を行います.

なお,ファイナルプロジェクトでは上図に示すワールドでロボットカーにMCLを実装します.

リファレンス

ワールドの作成

  • 次のWebots作業用ディレクトリを作成する.
    • C:\ユーザー\ユーザ名\webots
  • Webotsを起動する.
  • Cityワールドを開く
    • [ファイル]→[Open Sample World…]→[vehicles]→[city.wbt]
  • ワールドを開くとロボットカーが走り出すので,[Pause]ボタンをクリックして,[Reset Simulation]ボタンをクリックして,ロボットをスタート地点に戻す.
  • ワールドをrobot_car.wbtという名前で保存する.
    • [ファイル]→[ワールドファイルを名前を付けて保存する…]
      • \webots\robot_car\world\robot_car.wbtという名前で保存する.

コントローラの作成

  • [ウィザード]→[新規ロボットのコントローラ…]から以下を選択する.
    • 言語選択:Python
    • コントローラの選択:robot_car
  • シミュレーション窓の右横にエディタが開き,robot_car.pyが表示される.雛形コードの中身を全部消して,次のサンプルコードと置き換え保存する.
    import math             # mathモジュールのインポート
    from vehicle import Driver   # vehcleモジュールからDriverクラスのインポート
    
    driver = Driver()   # Driverクラスのインスタンスを生成
    steer_angle = 0     # ステアリング角に0[°]を代入
    speed = 20          # 速度に20[km/h]を代入
    
    driver.setSteeringAngle(steer_angle) # ステアリング角度の設定
    driver.setCruisingSpeed(speed)        # 巡行速度の設定
    
    while driver.step() != -1:  # driver.step()はシミュレーションの1ステップを進めるAPI
        #angle = 0.3 * math.cos(driver.getTime())
        #driver.setSteeringAngle(angle)
        print("time=%f" %driver.getTime()) # シミュレーション時間[s]の表示
  • 上のソースコードを説明します.説明をコメントとして記入しているので,ほとんど説明は不要かと思います.これは直進するだけのプログラムです.12,13行目でコメントアウトしている部分は,ステアリンク角度をcos関数で変化させています.driver.getTime()はシミュレーションがスタートしてからの経過時間[s]です.

コントローラの設定

  • シミュレーション窓の左欄からBmwX5→controller”autonomouos_vehecle”をクリックする.
  • Select controllerから上で作成したrobot_carを選択して保存する.

実 行

  • Reset Simulationボタン→Runボタン
  • トップ図のようにロボットが直進して,ターミナルに経過時間が表示される.

ハンズオン

  1. リファレンスを読んで,Webotsの自動運転用のシミュレーションソフトウェアの概要やAPIを理解しよう.
  2. サンプルコード12,13行目のコメントを外して,ロボットカーを走らせてみよう.
  3. サンプルコードのAPIだけを使って,ロボットカーをできるだけ遠くまで走らせてみよう.

終わり

 

 

Webots入門講座3:自動運転シミュレータ (Python)

$
0
0

Webots入門講座の3回目です.demura.netのサーバーを引っ越していたので,少し連載が遅くなりました.今まで少しアクセスが集中すると503エラーが多発して,ご不便をおかけしていたと思います.新サーバーに引っ越したので状況が改善されると思います.引き続き,demura.netをよろしくお願いします。

さて,今回は,Webotsの自動運転シミュレータを使ってBMW X5をPython言語により直進させるところまでを学びます.BMWのオーナーになった気分でやっていきましょう!

リファレンス

ワールドの作成

  • 次のWebots作業用ディレクトリを作成する.
    • C:\ユーザー\ユーザ名\webots
  • Webotsを起動する.
  • Cityワールドを開く
    • [ファイル]→[Open Sample World…]→[vehicles]→[city.wbt]
  • ワールドを開くとロボットカーが走り出すので,[Pause]ボタンをクリックして,[Reset Simulation]ボタンをクリックして,ロボットをスタート地点に戻す.
  • ワールドをrobot_car.wbtという名前で保存する.
    • [ファイル]→[ワールドファイルを名前を付けて保存する…]
      • \webots\robot_car\world\robot_car.wbtという名前で保存する.

コントローラの作成

  • [ウィザード]→[新規ロボットのコントローラ…]から以下を選択する.
    • 言語選択:Python
    • コントローラの選択:robot_car
  • シミュレーション窓の右横にエディタが開き,robot_car.pyが表示される.雛形コードの中身を全部消して,次のサンプルコードと置き換え保存する.
    import math             # mathモジュールのインポート
    from vehicle import Driver   # vehcleモジュールからDriverクラスのインポート
    
    driver = Driver()   # Driverクラスのインスタンスを生成
    steer_angle = 0     # ステアリング角に0[°]を代入
    speed = 20          # 速度に20[km/h]を代入
    
    driver.setSteeringAngle(steer_angle) # ステアリング角度の設定
    driver.setCruisingSpeed(speed)        # 巡行速度の設定
    
    while driver.step() != -1:  # driver.step()はシミュレーションの1ステップを進めるAPI
        #angle = 0.3 * math.cos(driver.getTime())
        #driver.setSteeringAngle(angle)
        print("time=%f" %driver.getTime()) # シミュレーション時間[s]の表示
  • 上のソースコードを説明します.説明をコメントとして記入しているので,ほとんど説明は不要かと思います.これは直進するだけのプログラムです.12,13行目でコメントアウトしている部分は,ステアリンク角度をcos関数で変化させています.driver.getTime()はシミュレーションがスタートしてからの経過時間[s]です.

コントローラの設定

  • シミュレーション窓の左欄からBmwX5→controller”autonomouos_vehecle”をクリックする.
  • Select controllerから上で作成した”robot_car”を選択して保存する.

 

実 行

  • [Reset Simulation]ボタン→[Run]ボタン
  • ロボットが直進して,ターミナルに経過時間が表示されれば成功.動かない場合は,[Reset]ボタン,[Run]ボタンを再度クリックしてください.

ハンズオン

  1. リファレンスを読んで,Webotsの自動運転用のシミュレーションソフトウェアの概要やAPIを理解しよう.
  2. サンプルコード12,13行目のコメントを外して,ロボットカーを走らせてみよう.
  3. サンプルコードのAPIだけを使って,ロボットカーをできるだけ遠くまで走らせてみよう.

終わり

 

Webots入門講座4:自分の位置を知ろう (Python)

$
0
0

Webots入門講座の4回目です.今回も前回に引き続き,Webotsの自動運転シミュレータを使います.BMW X5に搭載されているGPSを使い自分の位置(自己位置)を知る方法を学びます.

レファレンス

自己位置の取得

  • 自己位置の取得には内界センサ外界センサを使った方法があります.
    1. 内界センサ:ロボットの車速センサやステアリング角度センサなどの内部状態を知る内界センサを使い,その情報を使って自己位置を計算する方法をデッドレコニング(Dead Reckoning)とよびます.
    2. 外界センサ:GPS,LIDAR,カメラなどの外界センサの情報を使い自己位置を計算する方法.GPSセンサは自己位置を直接出力するので簡単に位置を取得できます.Webotsでは,ロボットにGPSノードを追加します.BMW X5にはGPSノードが組み込まれているので,APIを呼び出すだけ自己位置を取得できます.

GPSに関するAPI

  • enable(samplingPeriod): GPSの測定を可能にする.引数のsamplingPeriodでセンサのサンプリング時間[ms]を指定できる.
  • disable(): GPSの測定を不可能にする.
  • getSamplingPeriod(): サンプリング時間[ms]を取得する.
  • getValues(): GPSの測定結果(3次元ベクトル)を返す.値は座標系によりデカルト座標系の(x, y, z)[m]か世界測地系(WGS84)の(緯度,経度,高度)となる.
  • getSpeed(): 速度[m/s]を返す.
  • getCoordinateSystem(): 座標系を取得する.座標系はWorldInfoノードのgpsCoordinateSystemフィールドで定義されている.戻り値はWB_GPS_LOCAL_COORDINATEなら0,WB_GPS_WGS84_COORDINATEなら1である.

サンプルコード

''' robot_car2.py '''
import math                 # 数学モジュールのインポート
from vehicle import Driver  # vehcleモジュールからDriverクラスをインポート
from controller import GPS  # コントローラモジュールからGPSクラスをインポート

TIME_STEP = 60              # GPSのサンプリング時間 60[ms]  

driver = Driver()             # Driverクラスのインスタンスを生成
driver.setSteeringAngle(0.0)  # ステアリングの角度を0.0[rad]に設定
driver.setCruisingSpeed(20)   # 巡行速度を20[km/h]に設定

# GPS
gps = driver.getDevice("gps") # デバイス名から,そのクラスのインスタンスを生成
gps.enable(TIME_STEP)         # サンプリング間隔TIME_STEPでGPSからデータを取得可能

coordinate = gps.getCoordinateSystem()        # 座標系の取得
print("Coordinate system is ",coordinate)

while driver.step() != -1:
    angle = 0.03 * math.cos(driver.getTime()) # ステアリング角の計算
    driver.setSteeringAngle(angle)            # ステアリング角の設定
    
    # GPS
    values = gps.getValues()                  # GPSからデータを取得
    print("%g[s] position:(%g, %g, %g9[m]" % (driver.getTime(),values[0], values[1], values[2]))

    if driver.getTime() > 5.0:             # 5[s]経過したら
        driver.setCruisingSpeed(0.0)          # 停止
    上のサンプルコードは,ロボットに搭載されているGPSセンサを使いデータを取得するまでの一連の処理が書かれ,ロボットはスタートしてから5[s]でストップします.コードの各行にコメントを入れているので細かい説明は各行を読んでください.なお,このシミュレータでは座標系はデカルト座標系が設定されているのでGPSから取得した値の単位は[m]になります.普通,GPSセンサからデータを取得すると世界測地系で単位は[°]になり,[m]に変換する処理が必要になるケースが多いです.この例では,それが不要なので簡単ですね.

ハンズオン

  1. Webots入門講座3:自動運転シミュレータ (Python)で実施した要領で,新規プロジェクトrobot_car2を作成して,ワールドcity.wbtをワールドrobot_car2.wbtに上書き保存する.
  2. サンプルコードをコントローラプログラムとして,シミュレーションを実行して動作を確認しよう.
  3. サンプルコードを改良して,10[m]前進して停止させるプログラムを作ろう.
  4.  サンプルコードを改良して,Start地点から目標地点(進行方向x座標に30[m],左方向y座標に5[m])に走行して停止するプログラムを作ろう.
    • ヒント:GPSセンサからStart地点の座標を取得して,目標地点のGPS座標系で位置を計算する.ロボットが目標地点に近づくようにステアリング角を制御する.制御方法は比例制御で良い.
  5. サンプルコードを改良して,下図の黄色コースを1周する(Start地点から走行し,反時計まわりに1周してStart地点で停止する)プログラムを作ろう.
    • ヒント:現時点ではGPSセンサしか使えないので,黄色コース上で通過する地点(ウエイポイント)を何点か決めて,その点を順番に経由することで1周すれば良い.これをウェイポイントナビゲーションとよぶ.途中で障害物があるので,それを避けるように経由点を設定する.

プチプロジェクト

  • レファレンスを読んで,この自動運転シミュレータで使われているロボットカーBMW X5のモデルを調べて,デッドレコニングを実施しましょう.
    • ヒント:ロボットカーはアッカーマン機構なので,その運動学を調べてデッドレコニングを実装する.

終わり

 

Viewing all 757 articles
Browse latest View live