|
Raspberry Pi を用いたRobot(例えば、RT/RaspberryPI Mouseなど)の操作をROS(Robot Operating System)を用いて実行するためには、ROSをインストールする必要があります。ROSはUbuntuをサポートしているので、Ubuntu ディストリビューションをインストールします。ここでは、Raspberry Pi 3の cpu の メモリが1GBなので、Ubuntu Desktop ではなく、 Ubuntu Server 20.04LTS をインストールします。ここで使用するPCは Macです。
使用するRasPiはRaspberry Pi 3(Model B) です。その構成と機能は以下の通りです。
Raspberry Piを作動させるためには、電源用USB-microBケーブル、モニター(TV)との接続用 HDMIケーブル、USB接続のキーボードとマウスが必要です。Raspberry Piにはハードディスクが内蔵されていないので、microSDカードにOSをインストールして用います。16GBあるいは32GBのmicroSDを用意してください。microSDカードはそれほど高価ではないので新しい物を用意したほうが無難です。
Ubuntu Server の操作では、GUI の利用はできませんので、 コンソールを用いたコマンドラインで行います。従って、基本的にはPCから ssh 接続で操作します。Ubuntu OS の取扱説明はLinux OS 入門のページを参照ください
Ubuntu Server 20.04 をインストールした後で、ROSのインストール手順を説明します。2022年2月現在、ROSのLTS最新バージョンはROS Noetic Ninjemys です。サポートするプラットフォームは Ubuntu 20.04 です。Python3をサポートしています。
なお、2017年12月に、ROSの新しいバージョンROS2がリリースされています。ROS2は通信用ソフトとして汎用性の高いThe Data Distribution Service for real-time systems (DDS)を採用しています。(DDS は、最近開発された、 financial trading, air-traffic control, smart grid management, big data 処理などの応用分野で使用されるnetworking middlewareです。ROS2の中でROSを併用することはできます。ここでは、ROS2については説明をしません。ROS2 Galactic Geochelone のインストールの説明は、ROS2 の公式ページ を参照下さい。
なお、Ubuntu Server 20.04LTS(32 or 64bit) をインストールした Raspberry Pi 3 を ロボット(Raspberry Pi Mouse)に搭載して、リモートPCからSSH 接続で利用中に「host is down」が頻繁に起きます。この現象に対する対処の方法は不明なので、再度 Rasbeppry Pi の電源スイッチをオンにする必要があります。
Last updated: 2022.2.25
Ubuntu Serverのダウンロードとインストール |
microSDカードにインストールするイメージファイルをダウンロードする必要があります。microSDを挿す前に
$ diskutil list
と入力して、その後でmicroSDを挿して、(Linuxでは、コマンドはlsblk を使用してください)
$ diskutil list
と同じコマンドを入力します。この結果、例えば、/dev/disk2 (external, physical)が増えている時、これがmicroSDであることがわかります。できるなら新しいmicroSDを使用して下さい。
Raspberry Pi用のイメージファイルをダウンロードするために、まずRaspberry Pi の公式ページから Raspberry Pi Imager をダウンロード、インストールします。次に、この Raspberry Pi Imager を起動します。operating system の choose OS で、other general-purpose OS をクリックして Ubuntu の項に行き、Ubuntu Server 20.04LTS(32bit または64bit) を選択します。Choose Storage でmicroSD カードを選択して、write します。
書き込みが終わったら、ejectします。
$ diskutil eject /dev/disk2
microSD をRaspberry Pi に差し込んでブートする前に、Ubuntu のインストール解説に沿って以下の手順を踏みます。
microSD をPC に挿して、ファイルマネージャを起動して、“system-boot” partition にある network-config ファイルをテキストエディタで開き、Wi-Fi credentials を追加します。インターネット接続を有効にするためです。#wifis アンコメントして、以下のような記述にします。
wifis: wlan0: dhcp4: true optional: true access-points: "home network": password: "123456789"
home network を使用しているwifiの名前に、123456789 をこの自宅のwifiのパスワードに変更します。
以下の手順でインストールをおこないます。
microSDをRaspiに挿入して、起動すると、Boot が開始します。ログイン画面が表示されます。login: 後にubuntu と打ちます。すると、password を聞いてきますので、取り敢えず ubuntu と入力します。その後、パスワードの変更が要求されますので、対応します。すると、ログイン状態となります。この結果ユーザー名は ubuntu となります。ログインには変更したパスワードが必要です。
まず、aptのパッケージリストを更新してアップグレードしておきます。
$ sudo apt update $ sudo apt upgrade
時刻を日本時間に変更するために、
$ sudo timedatectl set-timezone Asia/Tokyo $ date
と入力して、確認します。WiFi のIP アドレスを確認するために、以下のコマンドを打ちます。
$ ip a ------ 1: lo:mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000 link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 inet 127.0.0.1/8 scope host lo valid_lft forever preferred_lft forever inet6 ::1/128 scope host valid_lft forever preferred_lft forever 2: eth0: mtu 1500 qdisc fq_codel state DOWN group default qlen 1000 link/ether b8:27:eb:c8:82:e9 brd ff:ff:ff:ff:ff:ff 3: wlan0: mtu 1500 qdisc fq_codel state UP group default qlen 1000 link/ether b8:27:eb:9d:d7:bc brd ff:ff:ff:ff:ff:ff inet 192.168.11.1/24 brd 192.168.11.255 scope global dynamic wlan0 valid_lft 172136sec preferred_lft 172136sec inet6 fe80::ba27:ebff:fe9d:d7bc/64 scope link valid_lft forever preferred_lft forever
Raspberry Pi のWiFiのIPアドレスは inet 192.168.11.1 であることが確認できます。リモートPCから操作するために、以下のコマンドを入力します。
$ sudo systemctl enable ssh
ここからは、リモートPCでの操作になります。Raspberry Pi からキーボードとモニターを外します。
ROSのインストールと設定 |
Raspi を操作するPCのターミナルから
$ ssh ubuntu@192.168.11.1
と入力します。パスワードが要求されるので、パスワードを入力します。これで、ラズパイと接続します。以後、PCのターミナルからのリモート操作となります。
以下、ROS Noetic Ninjemys のインストールの手順を説明します。「packages.ros.org.」からのソフトを受け入れるためにOSなどをセットアップします(長いですが全部でコマンド1行文です)。以下のコマンドを入力します。
$ sudo sh -c 'echo "deb http://packages.ros.org/ros/ubuntu $(lsb_release -sc) main" > /etc/apt/sources.list.d/ros-latest.list'
以下のコマンドでキーをセットアップする。
$ sudo apt install curl # if you haven't already installed curl $ curl -s https://raw.githubusercontent.com/ros/rosdistro/master/ros.asc | sudo apt-key add -
インストールするにあたって、始めに、Ubuntu package indexをアップデートする。
$ sudo apt update
次のコマンドでros-noetic-desktopをインストールする。GUIを含めた基本セットをインストールしたい場合は、ros-kinetic-desktop-fullを選択して、インストールしてください。(GUIを用いたシミュレーションをしない場合は、ros-kinetic-desktopでも十分です。)
$ sudo apt install ros-noetic-desktop
サイズが約470MBありますので、ダウンロードとインストールに30分以上の時間がかかります。ROS環境変数を設定するために、
$ echo "source /opt/ros/noetic/setup.bash" >> ~/.bashrc $ source ~/.bashrc
と入力して、bashファイルをシェルに組み込む。更に、PythonのROSパッケージなどを組み込むために
$ sudo apt install python3-rosdep python3-rosinstall python3-rosinstall-generator python3-wstool build-essential
とコマンドを入力する。これらのパッケージのインストールにも結構時間がかかります。
ROSを使用する前に、rosdepを初期化し、アップデートする必要があります。
$ sudo rosdep init $ rosdep update ----- reading in sources list data from /etc/ros/rosdep/sources.list.d Hit https://raw.githubusercontent.com/ros/rosdistro/master/rosdep/osx-homebrew.yaml Hit https://raw.githubusercontent.com/ros/rosdistro/master/rosdep/base.yaml Hit https://raw.githubusercontent.com/ros/rosdistro/master/rosdep/python.yaml Hit https://raw.githubusercontent.com/ros/rosdistro/master/rosdep/ruby.yaml Hit https://raw.githubusercontent.com/ros/rosdistro/master/releases/fuerte.yaml Query rosdistro index https://raw.githubusercontent.com/ros/rosdistro/master/index-v4.yaml -- 略 -- Add distro "melodic" Add distro "noetic" Add distro "rolling" updated cache in /home/ubuntu/.ros/rosdep/sources.cache
これで、一応のインストールは終了します。インストールが成功していれば、
$ roscore
とコマンド入力すると、ROSの本体が作動します。以下の通りに、ROSが起動されたことが表示されます。
------------------------------------------------------------------------------------------------------------------------------- ... logging to /home/ubuntu/.ros/log/704edcda-95ec-11ec-8c94-5d93f963c4c7/roslaunch-ubuntu-109484.log Checking log directory for disk usage. This may take a while. Press Ctrl-C to interrupt Done checking log file disk usage. Usage is <1GB. started roslaunch server http://ubuntu:44697/ ros_comm version 1.15.14 SUMMARY ======== PARAMETERS * /rosdistro: noetic * /rosversion: 1.15.14 NODES auto-starting new master process[master]: started with pid [109492] ROS_MASTER_URI=http://ubuntu:11311/ setting /run_id to 704edcda-95ec-11ec-8c94-5d93f963c4c7 process[rosout-1]: started with pid [109502] started core service [/rosout] -------------------------------------------------------------------------------------------------------------------------------
ROSの終了は「Ctrl」キーを押しながら「c」キーを押します。詳細は、この説明を読んでください。このページにあるコマンドをコピペする方がベターかもしれません。ROSの使い方ガイドは、このサイトの説明を参照してください。
ROSのプログラミング入門 |
ロボットに一連の動作をさせるためのプログラム群を納める作業スペースをcatkinワークスペースと言います。ROSを使用するにあたって最初にすることはこのcatkinワークスペースを作成することです。正確に言い換えると、例えば「catkin_ws」というわかりやすい名称のディレクトリを作成することです。このディレクトリの中にコードや設定ファイルを納めると、ロボットを動かす時に必要なもの一式が「catkin_make」というコマンド一つで生成できます。詳しい説明は公式チュートリアルを参照してください。そこからのコピペがベターかもしれません。
以下のコマンドを入力して、作業用のワークスペースを作成します。
$ source /opt/ros/noetic/setup.bash $ sudo apt install python3-empy # if pytho3-empy has not been installed $ mkdir -p ~/catkin_ws/src $ cd ~/catkin_ws/ $ catkin_make
このコマンド「catkin_make」はC言語のビルド・システムのmakeに対応していて、C++でのコードのコンパイルに関係する仕事をしてます。この結果、「source」ディレクトリの中に「CMakeLists.txt」が作成され、「catkin_ws」ディレクトリの下に「devel」と「build」という名称の二つのディレクトリが生成されます。いくつかの「setup.*sh」ファイルも生成されます。なお、この catkin_make は システム Pythoh3 を使用しますので、このPython へのパスが通っている必要があります。
このワークスペース関連の設定をシェルに読み込ませるために、
$ source ~/catkin_ws/devel/setup.bash
と入力する必要があります。
$ echo $ROS_PACKAGEAGEAGE_PATH
と打って、Terminalの標示からcatkin_ws/srcへのパスが確認できれば成功です。
ロボットに一連の動作をさせるための自作のプログラム・ファイル作成した時、これらを一つのパッケージにしてROSのワークスペース(catkin_ws)にビルドする必要があります。このパッケージ名をros_testとするとき、以下のようなコマンド入力が必要です。
$ cd ~/catkin_ws/src $ catkin_create_pkg ros_test std_msgs rospy roscpp
ここでのcatkin_create_pkgはパッケージの雛形を作ることを指示します。ros_test のフォルダーが作成されます。Terminalには
Created file ros_test/CMakeLists.txt Created file ros_test/package.xml Created folder ros_test/include/ros_test Created folder ros_test/src Successfully created files in /home/ubuntu/catkin_ws/src/ros_test. Please adjust the values in package.xml.
と表示されます。CMakeLists.txtはROSのcmakeというビルド・システムの設定ファイルです。package.xmlはROSのパッケージ管理システムが利用するファイルです。このファイルの中にはこのパッケージが利用するモジュール(rospy、roscpp、std_msgsなど)の依存関係が書かれています。ここまで来たら一度catkin_wsに戻って、catkin_makeする必要があります。
$ cd ~/catkin_ws $ catkin_make
このコマンドを実行すると、
Base path: /home/ubuntu/catkin_ws Source space: /home/ubuntu/catkin_ws/src Build space: /home/ubuntu/catkin_ws/build Devel space: /home/ubuntu/catkin_ws/devel Install space: /home/ubuntu/catkin_ws/install #### #### Running command: "make cmake_check_build_system" in "/home/ubuntu/catkin_ws/build" #### #### #### Running command: "make -j4 -l4" in Base path: /home/koichi/catkin_ws Source space: /home/koichi/catkin_ws/src Build space: /home/koichi/catkin_ws/build Devel space: /home/koichi/catkin_ws/devel Install space: /home/koichi/catkin_ws/install #### #### Running command: "make cmake_check_build_system" in "/home/koichi/catkin_ws/build" #### -- Using CATKIN_DEVEL_PREFIX: /home/koichi/catkin_ws/devel -- Using CMAKE_PREFIX_PATH: /home/koichi/catkin_ws/devel;/opt/ros/kinetic -- This workspace overlays: /home/koichi/catkin_ws/devel;/opt/ros/kinetic -- Using PYTHON_EXECUTABLE: /usr/bin/python -- Using Debian Python package layout -- Using empy: /usr/bin/empy -- Using CATKIN_ENABLE_TESTING: ON -- Call enable_testing() -- Using CATKIN_TEST_RESULTS_DIR: /home/koichi/catkin_ws/build/test_results -- Found gtest sources under '/usr/src/gtest': gtests will be built -- Using Python nosetests: /usr/bin/nosetests-2.7 -- catkin 0.7.8 -- BUILD_SHARED_LIBS is on -- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -- ~~ traversing 4 packages in topological order: -- ~~ - beginner_tutorials -- ~~ - raspimouse_ros -- ~~ - ros_start -- ~~ - ros_test -- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -- +++ processing catkin package: 'beginner_tutorials' -- ==> add_subdirectory(beginner_tutorials) -- +++ processing catkin package: 'raspimouse_ros' -- ==> add_subdirectory(raspimouse_ros) -- Using these message generators: gencpp;geneus;genlisp;gennodejs;genpy -- Generating .msg files for action raspimouse_ros/Music /home/koichi/catkin_ws/src/raspimouse_ros/action/Music.action -- raspimouse_ros: 10 messages, 2 services -- +++ processing catkin package: 'ros_start' -- ==> add_subdirectory(ros_start) -- Using these message generators: gencpp;geneus;genlisp;gennodejs;genpy -- Generating .msg files for action ros_start/GoUntilBumper /home/koichi/catkin_ws/src/ros_start/action/GoUntilBumper.action -- ros_start: 7 messages, 1 services -- +++ processing catkin package: 'ros_test' -- ==> add_subdirectory(ros_test) -- Configuring done -- Generating done -- Build files have been written to: /home/koichi/catkin_ws/build #### #### Running command: "make -j2 -l2" in "/home/koichi/catkin_ws/build" #### --------------- 以下略 -------------
と表示されます。これで、自作のパッケージがROSで利用できるようになります。ROSの中のディレクトリを探すとき、cdの代わりにroscdを使います。以下のコマンドでパッケージが構成されていることを確認しましょう。
$ roscd ros_test $ ls
ロボットを動かすための一連のプログラムをこのパッケージに書き込んでいくことになります。
Raspberry Pi Mouse のデバイス・ドライバーのインストール |
なお、ロボットを起動するためには、12v程度の電圧を供給する電源(3ピンコネクター付きリチウムイオン電池)が必要です。上記のロボット本体にセットで付属していますが、充電器は付いていません。LiPo充電器LBC-010とACアダプタ(12V5A)+VH3ピンコネクタへの変換ケーブルのセットが上記のRT 社から入手可能です。
以下での説明では主に Python を用いて書かれたコードを使用します。Linux や C 言語の知識は前提としませんが、ROS がインストールされていることは必須です。ROS のインストールの方法については、このページを参照して下さい。
Raspberry Pi Mouse Robot/RT社製小型移動ロボット
Raspberry Pi が Raspberry Pi Mouse ロボットに搭載されて、電池のコネクターが接続されていることを確認してください。WiFi 経由で Raspberry Pi への ssh 接続をするために必要なラズパイの IP アドレスがわかっているとします。
Raspberry Pi Mouse のメイン電源スイッチをオンにしてください。数分後、ラズパイの Ubuntu が起動したと思われたら、WiFi 経由で接続します。ラズパイのアドレスが192.168.11.1 であるとき、PCのターミナルから
$ ssh ubuntu@192.168.11.1
と入力して接続します。ここでは、ubuntu はラズパイにログインするときのユーザー名です。パスワードを入力して、ラズパイにログインします。
Raspberry Pi 入門のページにて説明した通り、ラズベリーパイには GPIO という40ピンのコネクターが付いています。この GPIO を操作して、ロボットを動かします。GPIO インターフェースとロボットの機器(デバイス)を接続するためには、ロボット専用のデバイス・ドライバーが必要です。ラズパイ・マウスのデバイス・ドライバーのソース・コードは GitHubのrt-net/RaspberryPiMouse にあります。
ラズパイにログインできたら、デバイス・ドライバーをインストールします。以下のようにGitHubからcloneします。
ubuntu@ubuntu:~$ git clone https://github.com/rt-net/RaspberryPiMouse.git ubuntu@ubuntu:~$ cd RaspberryPiMouse
/RaspberryPiMouse/src/drivers/というディレクターの中にC言語のソースコード rtmouse.c が配置されています。rtmouse.c をコンパイルする必要があります。ビルド用のbashファイルはutilsのディレクトリにあります。
ubuntu@ubuntu:~$ sudo apt install linux-headers-$(uname -r) ubuntu@ubuntu:~$ cd utils ubuntu@ubuntu:~$ ./build_install.ubuntu14.bash ---- make -C /usr/src/linux-headers-5.4.0-1052-raspi M=/home/ubuntu/RaspberryPiMouse/src/drivers V=0 clean make[1]: Entering directory '/usr/src/linux-headers-5.4.0-1052-raspi' make[1]: Leaving directory '/usr/src/linux-headers-5.4.0-1052-raspi' make -C /usr/src/linux-headers-5.4.0-1052-raspi M=/home/ubuntu/RaspberryPiMouse/src/drivers V=0 modules make[1]: Entering directory '/usr/src/linux-headers-5.4.0-1052-raspi' CC [M] /home/ubuntu/RaspberryPiMouse/src/drivers/rtmouse.o Building modules, stage 2. MODPOST 1 modules CC [M] /home/ubuntu/RaspberryPiMouse/src/drivers/rtmouse.mod.o LD [M] /home/ubuntu/RaspberryPiMouse/src/drivers/rtmouse.ko make[1]: Leaving directory '/usr/src/linux-headers-5.4.0-1052-raspi'
上記のようにデバイスドライバーの rtmouse.ko が作成されるはずです。ブザーが鳴って終了します。以下、プリフィックスの ubuntu@ubuntu は省略します。うまくいったら、rtmouse.ko が作成されていることを以下のように確認します。
$ cd /home/ubuntu/RaspberryPiMouse/src/drivers $ ls ---- Makefile Module.symvers rtmouse.ko rtmouse.mod.o Makefile.header_from_apt modules.order rtmouse.mod rtmouse.o Makefile.header_from_source rtmouse.c rtmouse.mod.c
この rtmouse.ko がデバイスドライバで、カーネル・モジュールと呼ばれます。linux のカーネルに後から組み込まれるモジュールです。カーネル・モジュール rtmouse.ko を linux カーネルに直接組み込む手続きが必要です。
ロボットのデバイスとGIOPピン番号との関係は「取扱説明書」に書いてある通りです。GPIOの状態を見てみましょう。/sys/class/gpio/というディレクトリがあることを確認します。ルート権限でlsを使います。
$ ls -l /sys/class/gpio/ ---- total 0 --w------- 1 root root 4096 Feb 25 15:31 export lrwxrwxrwx 1 root root 0 Feb 25 15:31 gpiochip0 -> ../../devices/platform/soc/3f200000.gpio/gpio/gpiochip0 lrwxrwxrwx 1 root root 0 Feb 25 15:31 gpiochip100 -> ../../devices/gpiochip1/gpio/gpiochip100 lrwxrwxrwx 1 root root 0 Feb 25 15:31 gpiochip504 -> ../../devices/platform/soc/soc:firmware/soc:firmware:expgpio/gpio/gpiochip504 --w------- 1 root root 4096 Feb 25 15:31 unexport ubuntu@ubuntu:~$ ls -a /sys/class/gpio/ . .. export gpiochip0 gpiochip100 gpiochip504 unexport
と表示されます。GPIOの入出力ファイルが存在することが確認できました。
ラズパイマウスを操作する手続きについては、上田隆一著『RaspberryPiで学ぶROSロボット入門』に詳しく説明されていますので、ここでの手続きは大枠でそれに沿っています。この書籍の説明をそのままコピーしたのでは、作動しないケースもありますので、その都度修正を加えています。デバイスドライバのシェルスクリプトも修正の必要がありました。以下の通りに、シェルスクリプトを作成してください。
------------------------------------------------------ #!/bin/bash/ cd ~/RaspberryPiMouse/src/drivers/ sudo insmod rtmouse.ko sudo chmod 666 /dev/rt* sleep 1 echo 0 > /dev/rtmotoren0 ------------------------------------------------------
このファイルを、pimouse_driver.bash という名前で home ディレクトリに保存してください。insmod という命令はrtmouse.ko を直接カーネルに組み込ませるコマンドです。これは bash ファイルなので、呼び出して、実行するときは、
$ source pimouse_driver.bash (または . pimouse_driver.bash)
とします。ロボットのブザーがピッーという音を出して、LEDが光ります。組み込みの成功の印です。ロボットのデバイスドライバがカーネルに組み込まれているので、/dev/ の下にデバイスファイルが作成されています。
$ cd $ ls -l /dev/rt*
とコマンドを入力すると、ロボットのデバイスファイルの一覧が表示されます。
crw-rw-rw- 1 root root 510, 0 Feb 25 15:45 /dev/rtbuzzer0 crw-rw-rw- 1 root root 511, 0 Feb 25 15:45 /dev/rtled0 crw-rw-rw- 1 root root 511, 1 Feb 25 15:45 /dev/rtled1 crw-rw-rw- 1 root root 511, 2 Feb 25 15:45 /dev/rtled2 crw-rw-rw- 1 root root 511, 3 Feb 25 15:45 /dev/rtled3 crw-rw-rw- 1 root root 508, 0 Feb 25 15:45 /dev/rtlightsensor0 crw-rw-rw- 1 root root 504, 0 Feb 25 15:45 /dev/rtmotor0 crw-rw-rw- 1 root root 506, 0 Feb 25 15:45 /dev/rtmotor_raw_l0 crw-rw-rw- 1 root root 507, 0 Feb 25 15:45 /dev/rtmotor_raw_r0 crw-rw-rw- 1 root root 505, 0 Feb 25 15:45 /dev/rtmotoren0 crw-rw-rw- 1 root root 509, 0 Feb 25 15:45 /dev/rtswitch0 crw-rw-rw- 1 root root 509, 1 Feb 25 15:45 /dev/rtswitch1 crw-rw-rw- 1 root root 509, 2 Feb 25 15:45 /dev/rtswitch2
rtled0を点灯したいときは、
$ echo 1 > /dev/rtled0
と入力します。消灯するときは
$ echo 0 > /dev/rtled0
とします。センサーを見たいときは
$ cat /dev/rtlightsensor0と入力します。
ステップモーターを回したいときには、まずロボットのモータースイッチを on に入れます。次に、
$ echo 1 > /dev/rtmotoren0 $ echo 400 400 1000 > /dev/rtmotor0
と順番に入力すると、モーターに通電し、400Hzで左右の車輪が順方向に回転します。1000ミリ秒回転し続けて、停止します。モーターに通電を止めるときは
$ echo 0 > /dev/rtmotoren0
とします。試験的にモーターを回転させるときは、ロボットの車輪を浮かせた状態にしておいてください。コマンドecho を使って、デバイスファイルに書き込むと、各デバイスを操作できます。色々と試して見てください。
ラズパイの終了は、
$ sudo shutdown now
と入力します。その後、ラズパイの緑色の点滅が停止してから電源スイッチを切ってください。
Raspberry Pi Mouse の簡単な操作 |
まず最初に、ロボット操作用の基本的なパッケージを作成します。パッケージの名前をpimouse_rosとします。
~/catkin_ws/src/にパッケージを作成するために、
$ cd ~/catkin_ws/src/ $ catkin_create_pkg pimouse_ros std_msgs rospy -----結果 Created file pimouse_ros/package.xml Created file pimouse_ros/CMakeLists.txt Created folder pimouse_ros/src Successfully created files in /home/ubuntu/catkin_ws/src/pimouse_ros. Please adjust the values in package.xml.
と入力します。catkin_create_pkgはパッケージを作成させるコマンドです。パッケージの名称の後に、ビルドに必要なライブラリのリストを書きます。rospyを明記しているのは、Pythonでコードを書くためです。(ROSのAPIのほとんどはC++とPythonで書かれています。)pimouse_ros というディレクトリができて、package.xmlとCMakelists.txt が自動的に作成されます。
$ cd pimouse_ros $ ls
と入力すると、生成されたファイルが表示されます。
pimoue_ros をワークスペースに組み込むために、
$ cd ~/catkin_ws $ catkin_make ---- 結果 Base path: /home/ubuntu/catkin_ws Source space: /home/ubuntu/catkin_ws/src Build space: /home/ubuntu/catkin_ws/build Devel space: /home/ubuntu/catkin_ws/devel Install space: /home/ubuntu/catkin_ws/install #### #### Running command: "cmake /home/ubuntu/catkin_ws/src -DCATKIN_DEVEL_PREFIX=/home/ubuntu/catkin_ws/devel -DCMAKE_INSTALL_PREFIX=/home/ubuntu/catkin_ws/install -G Unix Makefiles" in "/home/ubuntu/catkin_ws/build" #### -- Using CATKIN_DEVEL_PREFIX: /home/ubuntu/catkin_ws/devel -- Using CMAKE_PREFIX_PATH: /home/ubuntu/catkin_ws/devel;/opt/ros/noetic -- This workspace overlays: /home/ubuntu/catkin_ws/devel;/opt/ros/noetic -- Found PythonInterp: /usr/bin/python3 (found suitable version "3.8.10", minimum required is "3") -- Using PYTHON_EXECUTABLE: /usr/bin/python3 -- Using Debian Python package layout -- Using empy: /usr/lib/python3/dist-packages/em.py -- Using CATKIN_ENABLE_TESTING: ON -- Call enable_testing() -- Using CATKIN_TEST_RESULTS_DIR: /home/ubuntu/catkin_ws/build/test_results -- Forcing gtest/gmock from source, though one was otherwise available. -- Found gtest sources under '/usr/src/googletest': gtests will be built -- Found gmock sources under '/usr/src/googletest': gmock will be built -- Found PythonInterp: /usr/bin/python3 (found version "3.8.10") -- Using Python nosetests: /usr/bin/nosetests3 -- catkin 0.8.10 -- BUILD_SHARED_LIBS is on -- BUILD_SHARED_LIBS is on -- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -- ~~ traversing 2 packages in topological order: -- ~~ - pimouse_ros -- ~~ - ros_test -- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -- +++ processing catkin package: 'pimouse_ros' -- ==> add_subdirectory(pimouse_ros) -- +++ processing catkin package: 'ros_test' -- ==> add_subdirectory(ros_test) -- Configuring done -- Generating done -- Build files have been written to: /home/ubuntu/catkin_ws/build #### #### Running command: "make -j4 -l4" in "/home/ubuntu/catkin_ws/build" ####
とします。
ROSのページで説明した通り、ノード間での通信はTopicを介したメッセージの送信・受信としてプログラムされる。このロボットでのノードはデバイス・ファイルにある rtbuzzer、rtsensors、rtled、や rtmotors などである。
ブザーのノードを立ち上げ、他のノードからメッセージ(周波数)を受け取り、それをデバイス・ファイルに書き込むというプログラムを書きましょう。
#!/usr/bin/env python3 import rospy from std_msgs.msg import UInt16 def write_freq(hz=0): bfile = "/dev/rtbuzzer0" try: with open(bfile,"w") as f: f.write(str(hz) + "\n") except IOError: rospy.logerr("can't write to " + bfile) def recv_buzzer(data): write_freq(data.data) if __name__ == '__main__': rospy.init_node('buzzer') rospy.Subscriber("buzzer", UInt16, recv_buzzer) rospy.spin()
第1行目の#!/usr/bin/env python は、ファイルを実行ファイルとして用いる時の決まりです。実行ファイルとして読み込まれる時、if __name__ == '__main__':以下のコマンドから実行されます。
メセージの型を16ビット整数に定めるために、from std_msgs.msg import UInt16 と記述します。
コールバック関数 write_freq()とrecv_buzzer() を定義します。関数 write_freq(hz)では、デバイス・ファイル/dev/rtbuzzer0 を変数名 bfile として、この bfile を f という名称で開き、str(hz) の内容を書き込んでいます。書き込みが失敗するときの、エラー処理を except IOError で記述します。
その後、'buzzer'というトピックのノードを立ち上げ、このトピックのメッセージを購読して、rec_buzzer 関数で処理します。rospy.spin() は無限ループで受信を待つという意味です。
以上のスクリプトをファイル名 buzzer.py として/scripts/ディレクトリに保存します。
$ source ~/catkin_ws/devel/setup.bash $ roscd pimouse_ros $ mkdir scripts $ cd scripts $ nano buzzer.py $ chmod +x buzzer.py
と入力します。chmod +x buzzer.pyで、python ファイルを実行可能な状態にしておきます。
このプログラムを実行するために、3つのターミナルを起動します。ssh 接続でラズパイのターミナルを3つ立ち上げておきます。最初のターミナルで、roscoreを立ち上げます。
$ source ~/catkin_ws/devel/setup.bash $ roscore
2つ目のターミナルで、
$ source ~/catkin_ws/devel/setup.bash $ rosrun pimouse_ros buzzer.py
とノードを立ち上げます。topicをパブリッシュするために、3つ目のターミナルから
$ source ~/catkin_ws/devel/setup.bash $ rostopic pub -1 '/buzzer' std_msgs/UInt16 1000
と打ちます。'/buzzer'がトピック名で、メッセージの型がstd_msgs/UInt16であり、周波数がhz=1000という意味になります。すると、ブザーがピーとなります。停止するために
$ rostopic pub -1 '/buzzer' std_msgs/UInt16 0
と周波数をゼロとして入力します。音が止まります。1、2番目のターミナルで、[contrl + c]を入力して、python プログラムを終了します。
次に、距離センサーからの値をデバイス・ファイルから読み込んで、別のノードに伝える新しいノード 'lightsensors’ を作成します。トピックのメッセージの型を独自に定めます。距離センサーは4つありますので、4つの値のやりとりが必要です。各センサーに名前をつける必要もあります。型を定めるために、msgというディレクトリを作成します。以下のように入力します。
$ roscd pimouse_ros $ mkdir msg $ cd msg
msgディレクトリの中に以下のようなメッセージの型を定めるファイルを作成します。
int16 right_forward int16 right_side int16 left_side int16 left_forward int16 sum_all int16 sum_forward
このスクリプトをファイル名 LightSensorValues.msg として作成して、保存します。大文字小文字に注意。次に、ノード'lightsensors'を立ち上げるプログラムを作成します。scriptsディレクトリの中に、lightsensors1.pyというファイルを作成してください。
#!/usr/bin/env python3 import sys, rospy from pimouse_ros.msg import LightSensorValues rospy.init_node('lightsensors')
このスクリプトはノード'lightsensors'を立ち上げるだけの機能しかありません。from pimouse_ros.msg import LightSensorValues は'lightsensors'からのメッセージの型を組み込むためのコマンドです。このファイルを実行可能なファイルにするために、以下のように打ち込んでください。
$ roscd pimouse_ros/scripts $ nano lightsensors1.py $ chmod +x lightsensors1.py
roscoreを立ち上げて、
$ rosrun pimouse_ros lightsensors1.py
と打つと、エラーが出ます。なぜなら、pimouse_ros.msg というモジュールがまだ組み込まれていないからです。このモジュールを組み込むためには、catkin_makeが必要となります。
まず、package.xmlとCMakeLists.txtを編集します。package.xmlを開いて、以下のように二つの行のコメントを外して、上書き保存します。
------ <!-- Example: --> <author email="xxxxx@aol.com">Koichi Mashiyama</author> <!-- The *_depend tags are used to specify dependencies --> <!-- Dependencies can be catkin packages or system dependencies --> <!-- Examples: --> <!-- Use build_depend for packages you need at compile time: --> <build_depend>message_generation</build_depend> <!-- Use buildtool_depend for build tool packages: --> <!-- <buildtool_depend>catkin</buildtool_depend> --> <!-- Use run_depend for packages you need at runtime: --> <exec_depend>message_runtime</exec_depend> <!-- Use test_depend for packages you need only for testing: --> <!-- <test_depend>gtest</test_depend> --> -----
具体的には、
message_generation message_runtime
の2行のコメントを外します。これは、message_generation をビルドする時に、message_runtime を使うという意味になります。
次に、CMakeLists.txtを編集します。C言語のソースファイルをコンパイルさせるための makefile、CMake に読み込ませるファイルです。C言語の知識がない人はそうなんだと理解して進んでください。ディレクトリ pimouse_ros にある CMakeLists.txtを開いてください。変更する箇所は4箇所です。1つ目は、find_packageという行を見つけてください。
## if COMPONENTS list like find_package(catkin REQUIRED COMPONENTS xyz) ## is used, also find other catkin packages find_package(catkin REQUIRED COMPONENTS rospy std_msgs message_generation #追加する )
とmessage_genaraionという文を追加してください。
2つ目、add_message_filesというコマンドの行を探してください。デフォルトでは、その行以下が#でコメントアウトされています。#を外して、
## Generate messages in the 'msg' folder add_message_files( FILES LightSensorValues.msg )
と、LightSensorValues.msgを追加する。3つ目は、generate_messagesの行を探します。この行以下が#でコメントアウトされていますので、以下のように#を外します。
## Generate added messages and services with any dependencies listed here generate_messages( DEPENDENCIES std_msgs )
と修正します。
最後の4つ目は、catkin_packageの行を探します。この行以下の#のうちCATKIN_DEPENDSの行の#だけを外し、その行にmessage_runtimeを追加します。以下のようになります。
## CATKIN_DEPENDS: catkin_packages dependent projects also need ## DEPENDS: system dependencies of this project that dependent projects also need catkin_package( # INCLUDE_DIRS include # LIBRARIES pimouse_ros CATKIN_DEPENDS rospy std_msgs message_runtime # DEPENDS system_lib )
これで、CMakeLists.txtの修正は完了です。修正したファイルを上書き保存してください。
最後に、catkin_makeをします。
$ cd ~/catkin_ws/ $ catkin_make $ source ~/.bashrc
と入力します。これで、パッケージは完成です。
roscoreを立ち上げて、別のターミナルから
$ rosrun pimouse_ros lightsensors1.py
と入力して、エラーが出なければ、成功です。また、LightSensorValuesから生成されたファイルは以下のように入力すると、
$ cd ~/catkin_ws/devel/ $ find . | grep LightSensorValues --------- ./include/pimouse_ros/LightSensorValues.h ./share/common-lisp/ros/pimouse_ros/msg/_package_LightSensorValues.lisp ./share/common-lisp/ros/pimouse_ros/msg/LightSensorValues.lisp ./share/roseus/ros/pimouse_ros/msg/LightSensorValues.l ./share/gennodejs/ros/pimouse_ros/msg/LightSensorValues.js ./lib/python3/dist-packages/pimouse_ros/msg/_LightSensorValues.py ./lib/python3/dist-packages/pimouse_ros/msg/__pycache__/_LightSensorValues.cpython-38.pyc
と表示されます。
距離センサーからの値を読めるようにしましょう。そこで、lightsensors1.pyを以下のように書き換えます。
#!/usr/bin/env python3 import sys, rospy from pimouse_ros.msg import LightSensorValues if __name__ == '__main__': devfile = '/dev/rtlightsensor0' rospy.init_node('rtlightsensors') pub = rospy.Publisher('lightsensors', LightSensorValues, queue_size=1) rate = rospy.Rate(10) while not rospy.is_shutdown(): try: with open(devfile,'r') as f: data = f.readline().split() data = [int(e) for e in data ] d = LightSensorValues() d.right_forward = int(data[0]) d.right_side = int(data[1]) d.left_side = int(data[2]) d.left_forward = int(data[3]) # d.sum_all = sum(data) # d.sum_forward = data[0] + data[3] pub.publish(d) except: rospy.logerr("cannot open " + devfile) rate.sleep()
devfile = '/dev/rtlightsensor0'はデバイス・ファイルrtlightsensor0をdevfileという名称にします。pub = rospy.Publisher('lightsensors', LightSensorValues, queue_size=1)は、トピックlightsensorsを発信するインスタンスpubを作成します。メッセージの型はLightSensorValuesで定義されていて、バッファサイズが1という意味です。rate = rospy.Rate(10)は1秒間に10回の割合でプログラムを実行するというインスタンスを作成しています。while not rospy.is_shutdown():はプログラムが「ctrl+c」の入力で終了するまで無限ループで続くことを意味します。debfileの内容をdataに格納して、変数dの中に読み込んでいます。pub.publish(d)はd の内容を発信しています。#の行はコメント行で、エラーの関係で、ここでは無視します。このファイルをlightsensors2.pyという名前で保存します。roscoreを立ち上げ、
$ roscd pimouse_ros/scripts/ $ chmod +x lightsensors2.py $ rosrun pimouse_ros lightsensors2.pyと入力します。別のターミナルから
$ rostopic echo lightsensors --- right_forward: 19 right_side: 15 left_side: -6 left_forward: 14 --- right_forward: 31 right_side: 30 left_side: 12 left_forward: 30 ---
と入力すると、センサーの値が表示されます。rostopic echo lightsensorsは、トピック名lightsensorsからのメッセージを表示させるコマンドです。
距離センサーで計測する頻度を変えることができるように、プログラムを拡張します。以下のプログラムを作成して
#!/usr/bin/env python3 import sys, rospy from pimouse_ros.msg import LightSensorValues def get_freq(): f = rospy.get_param('lightsensors_freq',10) try: if f <= 0.0: raise Exception() except: rospy.logerr("value error: lightsensors_freq") sys.exit(1) return f if __name__ == '__main__': devfile = '/dev/rtlightsensor0' rospy.init_node('lightsensors') pub = rospy.Publisher('lightsensors', LightSensorValues, queue_size=1) freq = get_freq() rate = rospy.Rate(freq) while not rospy.is_shutdown(): try: with open(devfile,'r') as f: data = f.readline().split() data = [ int(e) for e in data ] d = LightSensorValues() d.right_forward = data[0] d.right_side = data[1] d.left_side = data[2] d.left_forward = data[3] d.sum_all = sum(data) d.sum_forward = data[0] + data[3] pub.publish(d) except IOError: rospy.logerr("cannot write to " + devfile) f = get_freq() if f != freq: freq = f rate = rospy.Rate(freq) rate.sleep()
lightsensors.pyとして、scriptsディレクトリに保存してください。パラメータ値の設定がないときは、初期値(hz=10)のままで作動します。上と同じく、roscoreを立ち上げ、
$ roscd pimouse_ros/scripts/ $ chmod +x lightsensors.py $ rosparam set lightsensors_freq 1 $ rosrun pimouse_ros lightsensors.py
と打つと、距離センサーが1秒間に1回光ります。
最後に、モーターの制御に関するプログラムを作成します。以下では、煩雑ですが、roscore の起動を含めて3つのターミナルを立ち上げる必要があります。
モーターのデバイス・ファイル rtmotor_raw_{l,r}0 へ回転数の周波数を送るノードを二つ作り、2種類のトピック、motor_rawとcmd_velを使います。motor_rawはこのロボット固有のものなので、新しくメッセージの型を作る必要があります。cmd_velはROSに付属しているシミュレータturtlesimで使用されている同名のトピックを使います。
motor_rawで使用するメッセージの型は以下のファイルを作成して
int16 left_hz int16 right_hz
ファイル名をMotoFreqs.msgとして、msgディレクトリに保存します。cmd_velの型はturtlesimに従いgeometry_msgs/Twistを使用します。この型の定義内容は以下のコマンドを打ち込むと表示できます。
$ rosmsg show geometry_msgs/Twist geometry_msgs/Vector3 linear float64 x float64 y float64 z geometry_msgs/Vector3 angular float64 x float64 y float64 z
linearは速度、angularは角速度に対応します。数値は64ビット浮動小数点形式です。方向は3次元となります。
MotorFreqs.msgは独自の型なので、モジュールに組み込むためにCMakeLists.txtに記述して置く必要があります。CMakeLists.txtを開いて、add_message_filesの下に以下のように追加します。
## Generate messages in the 'msg' folder add_message_files( FILES LightSensorValues.msg MotorFreqs.msg )
モーター操作用のプログラムを以下のように作成します。
#!/usr/bin/env python3 import sys, rospy, math from pimouse_ros.msg import MotorFreqs from geometry_msgs.msg import Twist class Motor(): def __init__(self): if not self.set_power(True): sys.exit(1) rospy.on_shutdown(self.set_power) self.sub_raw = rospy.Subscriber('motor_raw', MotorFreqs, self.callback_raw_freq) self.sub_cmd_vel = rospy.Subscriber('cmd_vel', Twist, self.callback_cmd_vel) self.last_time = rospy.Time.now() self.using_cmd_vel = False def set_power(self,onoff=False): en = "/dev/rtmotoren0" try: with open(en,'w') as f: f.write("1\n" if onoff else "0\n") self.is_on = onoff return True except: rospy.logerr("cannot write to " + en) return False def set_raw_freq(self,left_hz,right_hz): if not self.is_on: rospy.logerr("not enpowered") return try: with open("/dev/rtmotor_raw_l0",'w') as lf,\ open("/dev/rtmotor_raw_r0",'w') as rf: lf.write(str(int(round(left_hz))) + "\n") rf.write(str(int(round(right_hz))) + "\n") except: rospy.logerr("cannot write to rtmotor_raw_*") def callback_raw_freq(self,message): self.set_raw_freq(message.left_hz,message.right_hz) def callback_cmd_vel(self,message): forward_hz = 80000.0*message.linear.x/(9*math.pi) rot_hz = 400.0*message.angular.z/math.pi self.set_raw_freq(forward_hz-rot_hz, forward_hz+rot_hz) self.using_cmd_vel = True self.last_time = rospy.Time.now() if __name__ == '__main__': rospy.init_node('motors') m = Motor() rate = rospy.Rate(10) while not rospy.is_shutdown(): if m.using_cmd_vel and rospy.Time.now().to_sec() - m.last_time.to_sec() >= 1.0: m.set_raw_freq(0,0) m.using_cmd_vel = False rate.sleep()
このファイルにmotors1.pyと名前をつけて、scriptsディレクトリに保存してください。このスクリプトの説明を簡単にします。
from pimouse_ros.msg import MotorFreqs と from geometry_msgs.msg import Twist は、モーターへ送るメッセージの型を組み入れています。
クラスmotor() は5つのメソッド、__init__(self), set_power(self,onoff=False), set_raw_freq(self,left_hz,right_hz), callback_raw_freq(self,message), callback_cmd_vel(self,message), から構成されています。これらのメソッドのコードは読み込まれますが、実際の実行は、if __name__ == '__main__':から呼び出される時に、実現されます。
__init__(self):内では、モータに通電がないときはプログラムから抜けます。通電されている場合には、 rospy.on_shutdown(self.set_power)で、シャットダウンの入力があるときは、終了の処理を行いますが、そうでないときは、self.sub_raw = rospy.Subscriber('motor_raw', MotorFreqs, self.callback_raw_freq)を実行します。つまり、トピック'motor_raw'のメッセージの型をMotorFreqで受け取って、コールバック関数callback_raw_freqで処理します。
self.sub_cmd_vel = rospy.Subscriber('cmd_vel', Twist, self.callback_cmd_vel)は、トピック'cmd_vel'からのメッセージを受け取って、関数callback_cmd_velで処理します。
関数callback_raw_freqは受け取ったメッセージをそのままset_raw_freqに渡します。callback_cmd_velは、直進の速度(messege.linear.x)と角速度(messege.angular.x)を左右の周波数に変換して、set_raw_freqに渡します。この後、using_cmd_velの値をTrueとして、時刻をlast_timeに入れています。
main部分のwhile not rospy.is_shutdown():以下では、using_cmd_velの値がTrueであるとき、last_timeが1秒以上過去であれば、両方のモーターの周波数をゼロとして、using_cmd_velの値をFalseにします。言い換えると、トピックcmd_velを使ってモーターを回転させるときは、1秒間で回転が停止する。トピックmotor_rawを使用するときは、自動停止しませんので、停止のためのキー入力が必要です。
このファイルはこれ以降順次拡張されていきます。
このMotorFreqs.msgを組み込んだプログラムでモーターを操作するためには、catkin_makeをする必要があります。
$ cd ~/catkin_ws/ $ catkin_make
catkin_makeの後、roscoreが起動していないときは、roscoreを立ち上げ、二つ目のターミナルから
$ source ~/.bashrc $ roscd pimouse_ros/scripts $ chmod +x motors1.py $ rosrun pimouse_ros motors1.py
と入力して、motors1.pyを実行させます。別のターミナルを開いて、
$ rostopic pub /motor_raw pimouse_ros/MotorFreqs "left_hz: 100 (tab キーを打ち) right_hz:100"
と入力すると、hz=100でモーターが回転します。
止めるときは
$ rostopic pub /motor_raw pimouse_ros/MotorFreqs "left_hz: 0 (tab キーを打ち) right_hz:0"
と打つと停止します。geometry_msgsを用いてモーターを回転されるときは、例えば、
$ rostopic pub /cmd_vel geometry_msgs/Twist "linear: x: 0.0 y: 0.0 z: 0.0 angular: x: 0.0 y: 0.0 z: 1.0"
と入力すると、モーターが回転して、1秒後に停止します。