techno_memo

個人用の技術メモ。python・ROS・AI系のソフトウェア・ツールなどの情報を記載

Ubuntu18.04用 ROS環境開発構築

この記事の目的

 Ubuntu18.04 LTS の開発環境(ROS/Python/VS Codeなど)構築手順についてまとめる (Ubuntu16.04からのアップデート時の防備録)

1.Ubuntu18.04 LTSについて

Ubuntuは2年おきにLTS (Long Term Support)という長期サポート(5年)の安定版をリリースする。

これまで使っていた16.04は2021年にサポート切れとなるのと、Ubuntu 18.04を使用しているネット上の事例が増えてきたのでアップデートを試みる。

参考サイト

www.sejuku.net

qiita.com

2. Ubuntu16.04からのアップデート手順

Ubuntu16.04をすでに利用している場合アップデート用のコマンドを利用すると設定やアプリを引き継いでUbuntuの更新を実施することができる。

アップデートのコマンドは下記のようになる。

sudo apt update
sudo apt upgrade 
sudo apt autoremove            # 不要パッケージの削除
sudo apt dist-upgrade           # 保留パッケージの更新
sudo apt install update-manager-core           # アップデートマネージャのインストール
sudo do-release-upgrade           # アップデートの実施 -d を付与すると開発中のバージョンへの更新も行う

ただし、aptコマンドの依存関係が正しく判定されず保留中のパッケージが残る場合は正しくインストールできない。 原因となっているパッケージを apt-get purge xxx などで削除してすべてのパッケージを最新として保留パッケージがない状態にする必要がある。

参考サイト

paloma69.hatenablog.com

3. nvidiaGPUドライバの更新

Ubuntu 16.04ではnvidiaのグラフィックボードドライバを公式サイトから手動でダウンロードしてインストールする必要があった。 (これによりUbuntuのパッチ更新でログインループが発生するなどの問題も多く起きていた)

Ubuntu18.04ではnvidia用ドライバの更新を下記コマンドのみで実施できる。

sudo ubuntu-drivers autoinstall  #nvidia GPU用ドライバの更新 (推奨ドライバが自動的にインストールされる)
sudo reboot #再起動
nvidia-smi #ドライバがインストールされていること/どのバージョンがインストールされているかの確認

続けてCUDA/cuDNNをインストールする場合はnvidiaの公式サイトの案内(debファイルをローカルに落としてインストールする場合)下記のようにできる。(CUDA10.2の場合)

wget https://developer.download.nvidia.com/compute/cuda/repos/ubuntu1804/x86_64/cuda-ubuntu1804.pin
sudo mv cuda-ubuntu1804.pin /etc/apt/preferences.d/cuda-repository-pin-600
wget http://developer.download.nvidia.com/compute/cuda/10.2/Prod/local_installers/cuda-repo-ubuntu1804-10-2-local-10.2.89-440.33.01_1.0-1_amd64.deb
sudo dpkg -i cuda-repo-ubuntu1804-10-2-local-10.2.89-440.33.01_1.0-1_amd64.deb
sudo apt-key add /var/cuda-repo-10-2-local-10.2.89-440.33.01/7fa2af80.pub
sudo apt-get update
sudo apt-get -y install cuda

インストール後に.bashrcにCUDAのインストールパスを追加しておく

export PATH="/usr/local/cuda/bin:$PATH" export LD_LIBRARY_PATH="/usr/local/cuda/lib64:$LD_LIBRARY_PATH"

CUDNNについては公式サイトからダウンロードする (要ユーザー登録) その際、CUDAのバージョンにあった『cuDNN Library for Linux』をダウンロードし、展開後に下記コマンドでコピーする。

sudo cp -a cuda/lib64/* /usr/lib/cuda/lib64/
sudo cp -a cuda/include/* /usr/lib/cuda/include/

参考サイト taktak.jp

qiita.com

4. ROS melodicのインストール

Ubuntu 18.04ではUbuntu 16.04のROS kineticに変わりROS melodicをインストールする。

インストール手順はROS公式のインストール手順に従えば良い。

ただし、Ubuntu16.04からアップデートした場合ROS kineticの一部のパッケージが残っていることでmelodicで導入しようとするパッケージとの依存関係の干渉が発生してしまう可能性がある。

そのため下記コマンドを実施して古いROS関連パッケージを削除してからmelodicを導入したほうが良い。

sudo apt-get purge ros-* # ROS関連のaptパッケージの削除

5. その他の開発環境のインストール

Arduino IDE

Arduino公式サイトから"Linux 64 bits" を選択してダウンロードし、ファイルを展開後下記コマンドでインストール

sudo sh install.sh

Visual Studio Code と Pycharm

Ubuntu Softwareを起動し、Visual Studio Code/Pycharmで検索してインストール

ArduinoとPCの通信(シリアル通信)

この記事の目的

 ArduinoとPC間でのシリアル通信についてまとめる

1.Arduinoのシリアル通信機能

ArduinoでPCと信号の送受信を行う場合、USBケーブルを使ったシリアル通信が最も便利な手法である。

Arduino標準のSerialライブラリを使い下記の関数で信号の受け渡しを行うことができる。

参考サイト https://garretlab.web.fc2.com/arduino_reference/language/functions/communication/serial/

API リンク 概要
Serial.begin() リンク シリアル通信の初期化/bpsの指定
Serial.end() リンク シリアル通信の終了
Serial.setTimeout() リンク シリアル通信タイムアウト時間の指定
Serial.readStringUntil() リンク 指定した終端文字まで文字列を読み込む
Serial.println() リンク 指定した文字列を出力する

通信の速度はbpsで選択する。(300, 1200, 2400, 4800, 9600, 14400, 19200, 28800, 38400, 57600, 115200 など。送受信に必要な周期とデータ量を考慮して設定する。)

上記の表で挙げたのは送受信するデータは文字列であることを想定している。数値データは文字列に変換しカンマ区切りのデータで一括して送信することができる。下記にサンプルコードを示す。下記はデータの桁数をあらかじめ定めておき、終端が区切り文字";"で出力されるデータの送受信をすることを想定している。

/* serial_com_test.cpp */

/* header file */
#include "stdafx.h"
#include "serial_com_test.h"

/* static variable */
static int apl_cyc_count = 0;

#define READ_BUFSIZE  (7)   //受信バッファサイズ x.x,x.x; を想定(終端文字は含まない)
#define SEND_BUFSIZE  (50)  //送信用バッファサイズ
#define SEND_DATA_SIZE (6)  //整数桁3 小数点1 小数点以下2 を想定

//デバッグ用変数
static float deb_val1 = 0.0;
static float deb_val2 = 0.0;
static int keta = 0;

//通信の初期化用関数
void com_init (void)
{
     //Serial Communication initialization
    Serial.begin(115200);      //boudrate 115200
    Serial.setTimeout(50);      //read timeout for serial communication
    Serial.print("Serial Communication Start!");
    return;
}

//シリアル通信読み込み用関数
void com_read (void)
{
    char buff_A[4];
    char buff_B[4];
    if(Serial.available())  //読み込むデータが存在する場合
    {
        //終端データ";"までのすべてのデータを読み込む
        String str_buf = Serial.readStringUntil(';');
        keta = str_buf.length();
        if (str_buf.length() == READ_BUFSIZE )
        {
            str_buf.toCharArray(buff_A,4);
            deb_val1 = atoi(buff_A);
            Serial.println(deb_val1);

            str_buf.toCharArray(buff_B,4,4);  //先頭バイトの指定
            deb_val2 = atof(buff_B);
            Serial.println(deb_val2);
        }
        Serial.println(buff_A);
        Serial.println(buff_B);
    }
    return;
}

//シリアル通信読み込み用関数
void com_send (void)
{
    float deb_send_val1;
    float deb_send_val2;

    char test_str[SEND_BUFSIZE]={'\0'}; //配列を初期化用データで埋める
    char *ptr = test_str;

    deb_send_val1 = deb_val1 + 10.0;
    deb_send_val2 = deb_val2 - deb_val1;

    /*Send Acceralation information*/
    dtostrf(deb_send_val1,SEND_DATA_SIZE,2,ptr);
    ptr = ptr + SEND_DATA_SIZE;
    *ptr=',';  //区切り文字_token 
    ptr = ptr + 1;
    dtostrf(deb_send_val2,SEND_DATA_SIZE,2,ptr);
    ptr = ptr + SEND_DATA_SIZE;
    *ptr=';';  //end_token 
    Serial.println(test_str);
    return;
}

/*arduino 初期化処理*/
void setup()
{
    /*Initialize Communication */
    com_init();
}

/*arduinoメインループ*/
void loop()
{
     //50msec 周期実行
    interval<5000>::run([]{
        switch (apl_cyc_count)
        {
            case 0:
                com_read();
                break;
            case 1:
                //アクチュエータの制御などを実施(仮)
                break;        
            case 2:
                com_send();;
                break;
            default:
                //no action
                //Serial.println("Default");
                break; 
        }
        if (apl_cyc_count>=2)
        {
            apl_cyc_count = 0;
        }
        else
        {
            apl_cyc_count++;
        }
    });
}

 上記スクリプトで送受信した結果はArduino IDE / Teraterm などで確認することができる。

ここで、 PCのPythonスクリプトArduinoを通信させたい場合はライブラリ『Pyserial』を利用すると便利である。

Pyserialは下記コマンドでインストールすることができる。

 pip install pyserial

Pyserialではポート名とボーレート、タイムアウト時間を指定して関数readlineでバッファ読み込み、writeでバッファ書き込みを行う。

読み込みについては、通信状態によって不安定になることがあるため区切り文字までの文字数を明示的にしておくほうが良い。

#!/usr/bin/env python
# -*- coding: utf-8 -*-
import serial
import threading
import time
import re

###########################################
###  Serial Socket Communication Class  ###
###########################################
class Class_Serial_Socket(threading.Thread):

    ###################################
    #Connection information ##########
    COM_PORT_NAME = 'COM4'           #for Windows
    #COM_PORT_NAME = '/dev/ttyACM0'  #for Ubuntu
    BAURATE = 115200

    #############################################
    ###  Serial Communication Initialization  ###
    #############################################
    def __init__(self):
        #Initialize value for threading
        threading.Thread.__init__(self)
        self.terminate_request = False

        #Vehicle Control Signals sending to Arduino
        self.debval1 = 0.0  #initialize debag value 1
        self.debval2 = 0.0  #initialize debag value 2

        self.counter = 1.0;

        #initialize serial communication socket information
        self.ser_sock = serial.Serial(self.COM_PORT_NAME,self.BAURATE, timeout=0.01, writeTimeout=0.01)
        self.send_flg = True
        self.RECEIVE_LENGTH = 16;

        time.sleep(3)

    ####################################
    ###  Update RX data from Arduino ###
    ####################################
    def update_RX_data_from_arduino(self,str_b):
        try:
            str = str_b.decode()                 #Arduinoから受信した文字列のデコード
            #str_splitted =str.split(',')
            if (len(str) == self.RECEIVE_LENGTH):
                str_splitted = re.split('[,;]', str) 
                self.debval1 = float(str_splitted[0])      #1つ目の数字の取得
                print('debval1',self.debval1)
                self.debval2 = float(str_splitted[1])      #2つ目の数字の取得
                print('debval2',self.debval2)
        except:
            pass

    ##################################
    ###  Update TX data to Arduino ###
    ##################################
    def update_TX_buffer_to_arduino(self):
        #Generate sending buffer to Arduino
        #debug
        send_buffer = str(self.counter + 2.0)
        tempbuf = str(self.counter)
        send_buffer = send_buffer + "," + tempbuf
        send_buffer = send_buffer + ";" #for charactor end token
        self.counter = self.counter + 1.0
        if self.counter > 5.0:
            self.counter = 1.0
        try:
            self.ser_sock.write(str.encode(send_buffer))
        except Exception as e:
            print("例外args:", e.args)

        #    pass
            #print("write_error\n")

    ###############################
    ###  Main Periodic Function ###
    ###############################
    def run(self):
        while(1):
            if self.terminate_request == True:
                break;  #Finish  (User request)
            if self.send_flg == True:
                #try:
                #    self.update_TX_buffer_to_arduino()
                #except:
                #    print("Serial Communication Error (PC->Arduino)")
                self.update_TX_buffer_to_arduino()
                self.send_flg = False
            else:
                str = ""
                try:
                    str = self.ser_sock.readline()
                    self.update_RX_data_from_arduino(str)
                except:
                    print("Serial Communication Error (Arduino->PC)")
                self.send_flg = True
            time.sleep(0.050)

if __name__ == '__main__':
        sock_controler = Class_Serial_Socket()                 #Initialize Serial Communication
        sock_controler.start()

サンプルコードはgithubで公開している。

github.com

github.com

次回はROS TopicをArduinoと送受信する方法について説明する。

pygameを用いたゲームパッド操作機能の実装

この記事の目的

 pythonのライブラリpygameを用いてゲームパッドでユーザーの入力を読み込む処理を実装する。

使用したゲームパッド


ゲームパッド Logicool ロジクール F310r 国内正規品 3年間メーカー保証

参考となるサイト https://glorificatio.org/archives/1398

pygame

pygameとは

pythonのゲーム制作用ライブラリ 2Dの画面描画/音楽再生機能/ユーザー操作入力(マウス/キーボード/ゲームパッド)が充実しており、ゲーム以外にも処理結果の描画やUIとして利用することができる。

wiki

ja.wikipedia.org

機能/使い方の詳細

aidiary.hatenablog.com

インストール

windows (anacondaの場合)

pip install pygame

Ubuntu mateの場合

sudo apt-get install python-pygame

GUI描画(Hello World) とキーボード読み込み

初期化処理でスクリーンサイズなどを設定したあとで、30msec間隔をあけながらキーボードの状態を取得して 赤丸の位置を動かす処理は、下記のように記述できる。

#!/usr/bin/env python
# -*- coding: utf-8 -*-
import pygame
from pygame.locals import *
import sys
 
SCREEN_SIZE = (640, 480)  # 画面サイズ (横/縦)
STEP = 10       #キーボード/ハットスイッチの反応の良さ

if __name__ == '__main__':
    # Pygameを初期化
    pygame.init()
    screen = pygame.display.set_mode(SCREEN_SIZE)   # SCREEN_SIZEの画面を作成
    pygame.display.set_caption("window test")       # Windowタイトルの設定
    X_CENTER = int(SCREEN_SIZE[0]/2)
    Y_CENTER = int(SCREEN_SIZE[1]/2)
    [circle_x, circle_y] = [X_CENTER, Y_CENTER]     #円の初期位置を設定

    # 画面描画ループ
    while True:
        screen.fill((0,0,0))     # 画面を青色で塗りつぶす
        # イベント処理
        for event in pygame.event.get():    #×ボタンによる終了
            if event.type == QUIT:  # 終了イベント
                sys.exit()
        #  キーボード状態の取得
        pressed_keys = pygame.key.get_pressed()
        # 押されているキーに応じて画像を移動
        if pressed_keys[K_LEFT]:
            circle_x = circle_x - STEP
        if pressed_keys[K_RIGHT]:
            circle_x = circle_x + STEP
        if pressed_keys[K_UP]:
            circle_y = circle_y - STEP
        if pressed_keys[K_DOWN]:
            circle_y = circle_y + STEP

        #描画範囲の上下限チェック
        if circle_x< 0:
            circle_x = 0
        elif circle_x > SCREEN_SIZE[0]:
            circle_x = SCREEN_SIZE[0]

        if circle_y< 0:
            circle_y = 0
        elif circle_y > SCREEN_SIZE[1]:
            circle_y = SCREEN_SIZE[1]

        #描画
        pygame.draw.circle(screen, (255,0,0), (circle_x,circle_y), 10)
        pygame.display.update()  # 画面を更新
        pygame.time.wait(30)     # 30msec 待ち
        

コントローラの読み込み

ジョイスティックの初期化

下記処理を初期化部分に追加するとpygameジョイスティックを初期化できる。

    pygame.joystick.init()
    try:
        joy = pygame.joystick.Joystick(0) # create a joystick instance
        joy.init() # init instance
        print("Joystick Name: " + joy.get_name())
        print("Number of Button : " + str(joy.get_numbuttons()))
        print("Number of Axis : " + str(joy.get_numaxes()))
        print("Number of Hats : " + str(joy.get_numhats()))

F310の場合、軸やボタン数を下記のように取得できる。

Joystick Name: Controller (Gamepad F310)
Number of Button : 10
Number of Axis : 5
Number of Hats : 1

ジョイスティック(アナログバー)の読み込み

アナログバーは各軸について -1~1の小数値で得られる。 F310の場合axis(2)はLRキーの強さに対応する軸なので注意。 (下記は左スティックのみ有効としている)

            #ジョイスティック(アナログバー左スティック)状態の取得
            circle_x = int((joy.get_axis(0)+1) * X_CENTER)    #joystick(横軸)の方向キーはは-1~1の範囲で取得できる
            circle_y = int((joy.get_axis(1)+1) * Y_CENTER)    #joystick(縦軸)の方向キーはは-1~1の範囲で取得できる
            # axis(2)はL2/R2キーに対応
            #ジョイスティック(アナログバー右スティック)状態の取得
            #circle_x = int((joy.get_axis(3)+1) * X_CENTER)    #joystick(横軸)の方向キーはは-1~1の範囲で取得できる
            #circle_y = int((joy.get_axis(4)+1) * Y_CENTER)    #joystick(縦軸)の方向キーはは-1~1の範囲で取得できる

方向ボタン(ハットスイッチ)読み込み

方向ボタン(ハットスイッチ)は縦横軸それぞれを-1,0,1の離散値として取得できる

            #方向ボタン (ハットスイッチ)
            hat_input = joy.get_hat(0)

            if hat_input[0] == -1:  #
                circle_x = circle_x - STEP
            elif hat_input[0] == 1:
                circle_x = circle_x + STEP
            if hat_input[1] == 1:
                circle_y = circle_y - STEP
            elif hat_input[1] == -1:
                circle_y = circle_y + STEP

上記の3つの入力手段を切り替えることができるpygameスクリプトgithubに保存した。

github.com

次回は上記の処理をROSと結合して目標速度指令を送信し、turtlesimを動かす機能を実装する。

ROS入門 ワークスペース/パッケージ/ノード (python開発環境/vscode導入)

この記事の目的

pythonを用いたROSのパッケージの作成・ノードの実装・トピックの送受信についてまとめる。 Visual studio Codeを導入し、pythonスクリプトを実装しやすい環境を構築する。

pythonを用いたROSプロジェクト構築

ROSでは処理を実装して動作させるまでに下記のワークスペース/パッケージ/ノードを準備する必要がある。 以下に最低限のコマンドなどをまとめて記述する。

用語 内容
workspace ROSプロジェクト開発の作業用フォルダ
package 機能の集合体(開発時にmakeするプロジェクトの最小単位)
node プロセスとして相互にメッセージを通信する単位

1 ワークスペースの作成

下記チュートリアルに従ってcatkin_wsを作成する

wiki.ros.org

ターミナルを開きホームフォルダ直下にcatkin_wsを作成する ここで、setup.bashはcatkin_ws内に作成したパッケージの読み込みに必要となる設定である。下記スクリプトを記載しておくと起動時に自動的に読み込まれる。

$ mkdir -p ~/catkin_ws/src
# ホーム直下にcatkin_ws/srcを作成
$ cd ~/catkin_ws/src
# srcに移動
$ catkin_init_workspace
# ワークスペースの初期化を実施
$ cd ~/catkin_ws/
# catkin_wsに移動
$ catkin_make
# ワークスペースのビルドを実施
$ echo "source ~/catkin_ws/devel/setup.bash" >> ~/.bashrc
# bashrc にプロジェクトフォルダのsetup.bashを読み込む設定を追記
$ source .bashrc
#bashrcの読み込み (入力したときのみ必要。以降は起動時にbashrcから読み込まれる)

2 パッケージの作成

下記チュートリアルに従ってcatkin_ws内にパッケージを作成する

wiki.ros.org

$ cd ~/catkin_ws/src
# catkin_ws/srcに移動
$ catkin_create_pkg beginner_tutorials std_msgs rospy roscpp
# catkin_create_pkg [パッケージ名] [依存ライブラリ1] [依存ライブラリ2]...
#上記ではROSの標準メッセージ std_msgsとpython開発環境/C開発環境を読み込んでいる 

ここでパッケージ以下には下記のようなファイル・フォルダ構成としておく。(cmakelists.txtとpackage.xml以外は必要に応じて追加する)

フォルダ・ファイル名 説明
CMakeLists.txt パッケージ用のcmakeファイル(ビルドの依存関係の設定など)
package.xml rosプロジェクトの名前/依存関係を記載したファイル
include パッケージのヘッダファイル(外部公開用)
src C言語実装済みソフトウェア(使用するときのみ)
script python実装済みソフトウェア(使用するときのみ)
msg ユーザーが型定義するros message(使用するときのみ)
launch ユーザーが定義するlaunchファイル(使用するときのみ)

3 Visual Studio Codeの導入

上記まででプロジェクトの作成ができたので、pythonでのスクリプトを記述する。

pythonスクリプトの開発は標準インストールされているテキストエディタでもできるがVisual Studio Codeを用いるとコード補完などが動作するので効率が良い。

Ubuntu mate for Raspberry pi 用の Visual Studio Code のインストール手順

$ wget -qO - https://packagecloud.io/headmelted/codebuilds/gpgkey | sudo apt-key add -
#GPGキーの設定
$ sudo su
#管理者権限の付与
 . <( wget -O - https://code.headmelted.com/installers/apt.sh )
#インストール用スクリプトの読み込み

ただし、下記記事にあるようにUbuntu mate 16.04と最新バージョンのVS codeでは正しく動作しなかったので1.29にデグレした。

www.fabshop.jp

sudo apt-get install code-oss=1.29.0-1539702286 -y --allow-downgrades
#1.29へのデグレ
sudo apt-mark hold code-oss
#バージョンの固定 下記コマンドで解除可能
#sudo apt-mark unhold code-oss

実行後に下記の拡張機能を追加する。

f:id:sd08419ttic:20190625001709p:plain

上記設定後にコマンドパレットでpython2.7に切り替えるとVisual studio codeでROS対応したpythonコードを実行できる

下記チュートリアルに従ってtopicをノード間通信するpythonスクリプトを記述する。

wiki.ros.org

talker.py

#!/usr/bin/env python
# license removed for brevity
import rospy
from std_msgs.msg import String

def talker():
    pub = rospy.Publisher('chatter', String, queue_size=10)
    rospy.init_node('talker', anonymous=True)
    r = rospy.Rate(10) # 10hz
    while not rospy.is_shutdown():
        str = "hello world %s"%rospy.get_time()
        rospy.loginfo(str)
        pub.publish(str)
        r.sleep()

if __name__ == '__main__':
    try:
        talker()
    except rospy.ROSInterruptException: pass

listener.py

#!/usr/bin/env python
import rospy
from std_msgs.msg import String

def callback(data):
    rospy.loginfo(rospy.get_caller_id()+"I heard %s",data.data)
    
def listener():

    # in ROS, nodes are unique named. If two nodes with the same
    # node are launched, the previous one is kicked off. The 
    # anonymous=True flag means that rospy will choose a unique
    # name for our 'listener' node so that multiple listeners can
    # run simultaenously.
    rospy.init_node('listener', anonymous=True)

    rospy.Subscriber("chatter", String, callback)

    # spin() simply keeps python from exiting until this node is stopped
    rospy.spin()
        
if __name__ == '__main__':
    listener()

上記の2つのファイルを記述後にそれぞれのpythonファイルを実行するとtopic通信が行われることが確認できる。 次回はpythonジョイスティックやGUIを行いながらトピックの通信を行うスクリプトについて記述する。

ROS入門 (概要/用語/コマンド)

この記事の目的

 ROSを使った開発の考え方、手順(チュートリアルを通じたコマンドの使い方)についてまとめる

ROSの考え方/用語の整理

ROSの特徴や利点については下記サイトに細かく記載されている。

myenigma.hatenablog.com

特に、自動運転・ロボット関連の試作に便利なライブラリ(自己位置推定など)やデバッグ用のツールが充実しており、それらに関する試作を行う場合には非常に便利なフレームワークといえる。

ROSのプロセス/通信の概念・用語

上記のようにROSは便利なフレームワークではあるが使い方や固有の用語がかなり多い。 公式チュートリアル (http://wiki.ros.org/ja/ROS/Tutorials)を参考にしても良いが、 初級の時点でファイルシステムやパッケージファイルの詳細の説明をしており、直観的な 理解が難しいと感じた。そこで、今後説明しやすいように下記にROSでアプリケーションを 構築する際のプロセス/通信に関する概念と用語をまとめてみた。

参考 http://forestofazumino.web.fc2.com/ros/ros_basics.html

用語 内容
Node プロセス(処理)
Message ノード間の送受信
Master ノード・メッセージの名称管理をする
Topic 非同期で送受信するノード間信号
Subscriber Topicを受信する側のノード
Publisher Topicを送信する側のノード
Service 同期型(受信してすぐ処理を実行する)のノード間通信
Service Server Serviceを受けて実行結果を出力するノード
Service Client Serviceを要求して結果を受理するノード

上記については下記参考書の解説を読むとわかりやすい。


ROSではじめるロボットプログラミング―フリーのロボット用「フレームワーク」 (I・O BOOKS)

ROSコマンドの使い方 (チュートリアルを利用)

ROSではノードの起動や通信内容の確認、可視化をROSコマンドを用いて行う。 基本的には、下記の順で使用することが多い。 公式のチュートリアルにあるturtlesimを用いて使い方をまとめる。

1.roscoreの起動

roscore

各ノード・送受信信号の名前の管理、標準入出力処理を行う ROS上で処理を動作させる場合は必ず起動する必要がある (起動していない状態で別ノードを起動させようとするとroscoreの起動待ちになる)

2.ノードの起動

下記の2つの方法で起動できる。 オプションが多い場合はlaunchファイルを作っておくと良い。

rosrunコマンド

rosrun turtlesim turtlesim_node
# rosrun [package_name] [node_name]
rosrun turtlesim turtle_teleop_key
# turtlesim_nodeとは別のターミナルで起動する

コマンド rosrunを使いパッケージ名とノード名を指定して起動する apt-getで入れたライブラリでは問題ないが、自作で作ったパッケージの 場合パスを通しておく必要がある。

複数のノードを立ち上げる場合はそれぞれターミナルを立ち上げて実行する。

roslaunch

roslaunch beginner_tutorials turtlemimic.launch
#事前に下記チュートリアルに従った準備が必要
#roslaunch beginner_tutorials turtlemimic.launch

launch ファイル内に立ち上げたいノードと起動時のオプション (パラメータの有効/無効など)を渡すと1つのターミナルでノードをまとめて起動できる。ライブラリによっては最初からlaunchファイルで起動できるように提供されているものがある。(turtlesimはないのでチュートリアルに従って記述する必要がある)

3.動作結果の確認

ノードを立ち上げたあと、各ノードの状態・通信内容は下記のコマンドで確認する。

コマンドによる確認

送受信中の信号一覧の表示には下記を利用する。 rostopic list では信号の送受信が成立していなくても、 受信待ちの状態となるだけでリストに出力されることに注意する必要がある。 信号が狙いの周期で更新できているかは rostopic hzなどを用いたほうが良い。

# ROSで通信している全信号リスト
rostopic list

# ROSで通信している信号の出力
# rostopic echo [topic名]
rostopic echo /turtle1/pose

#表示例
---
x: 5.544444561
y: 5.544444561
theta: 0.0
linear_velocity: 0.0
angular_velocity: 0.0
---


# ROSで通信している信号の更新周期の出力
# rostopic hz  [topic名]
rostopic hz /turtle1/pose

#表示例
subscribed to [/turtle1/pose]
average rate: 62.515
    min: 0.015s max: 0.017s std dev: 0.00047s window: 61
average rate: 62.519
    min: 0.014s max: 0.017s std dev: 0.00052s window: 123

GUIによる確認

コマンドによる確認の他に、rosのGUI機能rqt_graphでノードとトピックの関係を 可視化して接続関係を確認することができる。

# GUIツール rqt_graphを用いたノードの通信状態の可視化
rosrun rqt_graph rqt_graph

f:id:sd08419ttic:20190619225134p:plain

また、各トピックの波形 (時系列変化)を表示することもできる。

# GUIツール rqt_graphを用いた波形の時間変化の可視化
rosrun rqt_plot rqt_plot

f:id:sd08419ttic:20190619225554p:plain

rvizによる確認

ROSで用意された形式に従って位置や速度情報を出力するとロボットが空間でどのような動きをしているかをrvizを使って確認することができる。 (tfの発行なども必要なので下記チュートリアルに従う)

wiki.ros.org

rviz

f:id:sd08419ttic:20190619231201p:plain

4.動作結果の保存

動作中のノード間でどのような信号の送受信が行われたのかを保存することができる。この機能を用いることで同じカメラ信号のrosbag信号を流しながら自己位置推定処理のデバッグをシミュレーションで行うなどの使い方が可能になる。

#全ての送受信信号の保存 (ターミナルのパスにbagファイルが生成される)
rosbag record -a
#bagファイルを再生する
#再生中は記録時と同じタイムスタンプでトピックの送受信が行われる
rosbag play recorded1.bag  

よく使うコマンドリストのまとめ

https://qiita.com/tomoyafujita/items/13076d37bcac05a83530

https://raspimouse-sim-tutorial.gitbook.io/project/ros_tutorial

用語 内容
roscore マスターノードの起動 (rosを使用する際は必須)
rosrun [ノード名] ノードの起動
roslaunch [launchファイル名] launchファイルを用いたノード起動
rostopic list ros上で通信しているtopicのリスト出力
rostopic echo [topic名] topic名の内容の出力
rostopic hz [topic名] topicの更新周期の出力
rosbag record -a ros上で通信しているtopicをbagファイルに保存
rosrun rqt_graph rqt_graph rqt_graphの起動
rviz rvizの起動

次回はpythonを使ったノードの開発・トピックの通信例についてまとめる。

Raspberry pi 開発環境について(Ubuntu Mate設定/ROS導入)

この記事の目的

 RaspberryPi3(with ROS/Python) を使った電子工作の環境構築手順についてまとめる

 ROSを使ったロボット制御のソフトウェアを実装するため下記を導入する。

  • Ubuntu Mate 16.04

  • ROS Kinetic

必要なハード

下記記事のハードを用い、Raspberry pi 3 model B を使用する。

sd08419ttic.hatenablog.com

下記の手順はWindows PC で必要なソフトのダウンロードやmicroSDカードへの書き込みなどを行うことを前提とする。

環境構築手順

1.SDカードの初期化

Raspberry pimicroSDカードにOSを書き込む必要がある。

公式サイトではツールSDCardFormatterでFAT32に初期化する手順を推奨しているが、SDカードのサイズが64GB以上の場合exFATに自動的に変換してしまうので注意が必要。

下記のIOデータのハードディスクフォーマッタではフォーマット時にFAT32を明示的に選択することができる。

www.iodata.jp

2.OSイメージの焼き込み

現在(2019.6)時点で、公式サイトのUbuntu Mate は 18.04に更新されている。

Ubuntu Mate 18.04 に対してROSを入れることも可能なようであるが、まだリリースされてから日が浅くトラブルも多いと予想できるので、 ここではUbuntu 16.04を導入する。Ubuntu 16.04はすでに公式サイトからはダウンロードできなくなっているが、下記サイトからダウンロード可能である。 (torrent形式なのでBitTorrentなどを用いてダウンロードする必要がある)

ubuntu-pi-flavour-maker.org

ダウンロードしたubuntu-mate-16.04.2-desktop-armhf-raspberry-pi.img.xz は7.zipでimgファイルに展開する

sevenzip.osdn.jp

展開したimgファイルを下記のWin32 Disk ImagerでmicroSDカードに焼きこむ

sourceforge.net

3.初期設定

上記までの手順でUbuntu Mateを焼きこんだmicro SDカードを、Raspberry pi の SDカードスロットに差してmicro USBから電源供給すると Raspberry pi 3が起動する。

Wifi/地域設定/キーボード設定をインストーラーはインストーラーの手順に従って実施すればできる。

システムの更新

Mate Terminalを開いて下記コマンドを実行

sudo apt-get update 
sudo apt-get upgrade

その他初期設定に関する記事(画面の最大化なども便利)

pinky-blog.com

上記を実施するとfirefoxがクラッシュする。(バージョンによって起動しないとのこと)ブラウザにこだわりがなければ下記でchromiumを導入してしまった方が早い。

sudo apt install chromium-browser

日本語入力対応

地域設定をしておくとGUI表示はデフォルトで日本語になる 言語設定が必要なのでシステム⇒設定⇒ユーザー向け⇒言語サポートからインストールし、入力形式をfcitxに変更する 下記に画像付きの解説がされている。

deviceplus.jp

IP固定

Windows PCからリモートでのログインやデータの受け渡しのために、IPを固定しておくと便利である。 Wifiであれば、画面右上のネットワークアイコン以下のGUIを使って設定が可能である

https://qiita.com/dendensho/items/ab63e4b343607d832f21

ファイル共有設定

sambaのインストールと設定行い、Raspberry pi のファイルをWindows PC からアクセス可能にできる

sudo apt-get -y install samba

上記を実施後、下記サイトにある『UI を使って samba を設定する(おまけ)』に従うとGUIを使ってsambaの共有設定ができる。

https://pinky-blog.com/raspberry-pi/nas-samba-server-ubuntu-mate/

リモートデストップの有効化

下記コマンドでxrdpをインストールする

sudo apt-get -y install xrdp

その後、下記サイトに従って暗号化レベルの変更と日本語キーボード設定を追加する (日本語キーボード設定がないと円マークなどが正しく入力できなくなる)

algorithm.joho.info

4. ROSのインストール

公式の手順に従いros-kineticをインストールする。

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-key adv --keyserver hkp://ha.pool.sks-keyservers.net:80 --recv-key 421C365BD9FF1F717815A3895523BAEEB01FA116
sudo apt-get update
sudo apt-get upgrade
sudo apt-get install ros-kinetic-desktop-full
sudo apt install python-roslaunch

次にrosのパッケージ管理機能の初期化/更新を行う

rosdep init
rosdep update

最後に環境変数にROSのパスを通す (ROSのコマンドを利用するために必要)

echo "source /opt/ros/kinetic/setup.bash" >> ~/.bashrc
source ~/.bashrc

上記まででRaspberry pi でROSを使う準備が整う。 ROSのcatkin_workspaceの作り方などについては今後別記事で説明する。

Raspberry pi 開発環境について(ハードウェア)

この記事の目的

 Raspberry pi の電子工作の開発環境について必要なハードウェアに関する情報を忘備録として整理する。

必須ハード

Raspberry pi 本体

カメラを使った画像認識などをすることを考慮すると、なるべく高スペックなものが望ましい。

2019年6月現在、下記のRaspberry pi 3 model B+が、最新かつ高スペックなRaspberry piである。


Raspberry Pi3 Model B+ ボード&ケースセット

ただし、1つ前のモデルであるRaspberry pi 3 model Bとのスペック差はさほどない。(CPUクロック数のわずかな上昇と通信速度の上昇程度)のと、Pi3の方が発売されてからの期間が長く各種開発環境の動作報告も多いので 以降の記事ではRaspberry pi 3の利用を前提として記載する。


Raspberry Pi3 Model B ボード&ケースセット

AC電源アダプタ

Raspberry Pi 3は micro USB type B端子での電力供給が必要となる。ただし、消費電流が2.5Aとなることからスマホ等のACアダプタでは対応できない可能性が高いため動作確認できているACアダプタを利用することを推奨する。 また、電源ボタンがなくケーブルからの電力供給の有無で起動を判定するため、頻繁な起動/終了の繰り返しで本体の端子が痛む可能性がある。スイッチボタンによる電力の遮断ができる下記のようなACアダプタを使うと便利である。


Raspberry Pi用電源セット(5V 3.0A)-Pi3フル負荷検証済

micro SDカード

Raspberry PiではOS等のソフトウェアをmicroSDカードに保存する必要がある。OSイメージ+基本的なツールを導入するための最低限の必要容量は4GB程度以上だが、今回の用途ではROS環境一式やカメラでの計測データを保存する必要 があるため32GBのものを利用する。 (なお、32GBを上回る容量の場合、SDカードをFAT32でフォーマットする使うツールに気を付ける必要がある。別途記載予定)


東芝 Toshiba microSDHC 32GB + SD アダプター + 保管用クリアケース [バルク品]

また、インストール手順でPCからmicro SDカードへの書き込みをする必要がある。PCにmicro SDを読み込む手段がない場合にはUSBのSDカードリーダーが必要となる。 (速度にこだわらなければ、最近は100均などでも購入可能)


Transcend USB 3.0 Super Speed カードリーダー (SD/SDHC UHS-I/SDXC UHS-I/microSDXC UHS-I 対応) ブラック 2年保証 TS-RDF5K

マウス/キーボード/HDMIケーブル

Raspberry pi の操作に利用する。マウス/キーボードはUSB接続のものであればよほど問題はないが、無線接続したい場合は動作実績があるものを利用する方が無難。

初期設定を済ませると、デスクトップPCからリモート接続して利用することも可能となるためあまりこだわらなくてもよい。

モバイルバッテリ

前述したように、Raspberry pi 3 は micro USB type Bによる給電が可能なのでモバイルバッテリからの電源供給ができる。ただし、最近のモバイルバッテリは消費電流が低い場合に省電力モードになってしまったり、 Raspberry pi のピーク時の2.5Aを出力できないなどの場合があるため、動作実績があるものを選んだほうが良い。下記サイトで実機での確認がされている。実際に私が試したところAnker PowerCore 10000、 cheero Power Plus 10050mAhともに問題はなかった。

消費電力が大きなRaspberry Pi3に最適のモバイルバッテリーは? - 猿まね電子工作

カメラ

Raspberry pi では専用のカメラモジュールによる画像取得とPC等で使われるUSB Webカメラによる画像取得が可能である。

カメラモジュールは小型・軽量で省電力ではあるが、取り付けなどに苦労する。下記のような台座とセットになっているものの方が良い。


For raspberry pi カメラモジュール 5MP Raspberry Pi 3 b+ / Pi Zero Camera とケース500W画素 感光チップOV5647センサー

Webカメラは、台座が安定してHD撮影可能なものとして下記などが良い。


LOGICOOL HDウェブカム フルHD動画対応 C615

ブレッドボード/ジャンパハーネス

Raspberry pi のGPIOに各種の電子部品を接続する際に必要となる。ジャンパハーネスは端子にオス-メスの組み合わせがあるので一定数まとめ買いしておいた方が良い。


ELEGOO 120pcs多色デュポンワイヤー、arduino用ワイヤ—ゲ—ジ28AWG オス-メス オス-オス メス –メス ブレッドボードジャンパーワイヤー

ブレッドボードはいろいろな場所への取り付けに対応できるよう小型/横長タイプで複数用意しておいた方が良い。


ELEGOO 400タイポイント ブレッドボード3PCS 、Arduino用ジャンパーワイヤ 4電源レール

次回はRaspberry pi の環境構築 (OS設定/ROSの導入/開発ツール類の設定)について記述する。