2016年12月12日月曜日

[コラム]ROSで始めるロボティクス(11) ー オムニホイールで全方向移動可能ロボットを作る 2



前回はロボットの車体部分を作成しました。それでは、Raspberry PiのGPIOを使い、モータードライバを制御することでロボットのモータを回転してみましょう。まずはOSインストールからです。


Raspberry pi 2 にUbuntu 14.04をインストールする

Ubuntuのサイト
https://wiki.ubuntu.com/ARM/RaspberryPi
より、Download 2015-04-06-ubuntu-trusty.zip をダウンロード、展開します。

展開したdmgファイルをSDカードに書き込みします。次はMacでの手順例です。

まずは、書き込み対象のSDカードを判定します。もし、間違えて指定した場合、間違えた先のデータが綺麗に消えてしまいます。慎重にいきましょう。
SD挿入前に次のコマンドを実行します。

$ df -h

そしてSD挿入後に再度実行します。

$ df -h

SDカードの挿入前、挿入後で増えているのがSDカードのデバイスファイルです。例えば/dev/disk2s1とか/dev/disk3s1とかになります。
書き込み対象となるSDのパーティーションをアンマウントします。
sudo diskutil unmount /dev/disk3s1
他には、ディスクユーティリティを開いてSDカードのそのパーティーションをアンマウントする方法もあります。

SDカードはそのままです。抜かないでください。

たとえばdisk3s1ならばs1を除いたdisk3がデバイスネームです。
次のコマンドで書き込みます。デバイスネームの前にrを書き込むのがポイントです。
例えば、/dev/disk3s1 は /dev/rdisk3 となります。

sudo dd bs=1m if=2015-04-06-ubuntu-trusty.img of=/dev/rdisk3

書き込みには結構時間がかかります。

ルートリサイズ

SDカードの全容量が利用可能となるように設定します。

$ sudo fdisk /dev/mmcblk0

2番目のパーティションを削除します (d, 2), それから再作成します。(n, p, 2, enter, enter), そして (w)を押して保存して終了します。

再起動してから次のコマンドを実行します。

$ sudo resize2fs /dev/mmcblk0p2

SWAPの作成

初期状態ではSWAPパーテーションがありません。SWAPファイルを準備しておきましょう。

$ sudo apt-get install dphys-swapfile

WIFIファームウェア

WIFIを使用する場合、linux-firmwareのインストールが必要です。

$ sudo apt-get update
$ sudo apt-get install linux-firmware
$ sudo reboot

SSHサーバー

他のPCからSSHで接続してメンテナンスできるようにsshのインストールをしておきます。

$ sudo apt-get install openssh-server

GPIOでソフトウェアPWM制御を行う

PWM制御とは、半導体を使った電力制御方式で、オンとオフの繰り返しスイッチングを行い、出力される電力を制御します。Raspberry Piもハードウェア制御のPWMが行えるGPIOを持っていますが、数が限られています。
そこでソフトウェア制御によるPWMを利用します。ハードウェア制御のPWMには精度は劣りますが、モータの回転制御に使用する分には十分です。


WiringPiのインストール

WiringPiはRaspberry PiのGPIOを制御するためのC言語ライブラリです。ソフトウェアPWM制御を行うことも可能です。またラッパーによりPythonから使用することが可能です。

sudo apt-get install libi2c-dev
sudo apt-get install git
sudo apt-get install git-core
sudo apt-get install build-essential
cd /opt
sudo git clone git://git.drogon.net/wiringPi
cd wiringPi
sudo ./build

cd /opt
sudo git clone https://github.com/WiringPi/WiringPi-Python.git
cd WiringPi-Python
sudo git submodule update --init

モーターの動作テスト

それではWiringPiを使い、モーターが正しく回るかテストしてみましょう。

// Include header file
#include <wiringPi.h>

// Define GPIO
#define GPIO_00 17
#define GPIO_02 27
#define GPIO_03 22

#define GPIO_01 18
#define GPIO_04 23
#define GPIO_05 24

#define GPIO_23 13
#define GPIO_24 19
#define GPIO_25 26

#define GPIO_27 16
#define GPIO_28 20
#define GPIO_29 21

int vref[] = {GPIO_00, GPIO_01, GPIO_27, GPIO_23};
int in1[]  = {GPIO_02, GPIO_04, GPIO_28, GPIO_24};
int in2[]  = {GPIO_03, GPIO_05, GPIO_29, GPIO_25};


/**
 * motor 0-3
 * rotate 0 or 1
 */
void run_motor(int motor, int rotate) {
    int vin1 = rotate == 0 ? 1 : 0;
    int vin2 = rotate == 0 ? 0 : 1;
    digitalWrite(in1[motor], vin1);
    digitalWrite(in2[motor], vin2);
    digitalWrite(vref[motor], 1);
}

void break_motor(int motor) {
    //digitalWrite(vref[motor], 0);
    digitalWrite(in1[motor], 1);
    digitalWrite(in2[motor], 1);
}
void stop_motor(int motor) {
    digitalWrite(vref[motor],0);
    digitalWrite(in1[motor], 0);
    digitalWrite(in2[motor], 0);
}

void foward() {
    stop_motor(1);
    stop_motor(3);
    run_motor(0, 0);
    run_motor(2, 1);
}

void back() {
    stop_motor(1);
    stop_motor(3);
    run_motor(0,1);
    run_motor(2,0);
}

void right() {
    stop_motor(0);
    stop_motor(2);
    run_motor(1,0);
    run_motor(3,1);
}

void left() {
    stop_motor(0);
    stop_motor(2);
    run_motor(1,1);
    run_motor(3,0);
}
void break_all() {
    break_motor(0);
    break_motor(1);
    break_motor(2);
    break_motor(3);
    delay(200);
    stop_motor(0);
    stop_motor(1);
    stop_motor(2);
    stop_motor(3);
}
int main(void) {
    // Initialize WiringPi
    if(wiringPiSetupGpio() == -1) return 1;

    // Set GPIO pin to output mode
    for(int i = 0; i < 4; i++) {
        pinMode(vref[i], OUTPUT);
        pinMode(in1[i], OUTPUT);
        pinMode(in2[i], OUTPUT);
    }
   
    // Spin motor

    foward();
    delay(3000);
    break_all();

    back();
    delay(3000);
    break_all();

    right();
    delay(3000);
    break_all();

    left();
    delay(3000);
    break_all();

    return 0;
}

まず、wiringPi.hをインクルードしてWiringPiの基本機能が使えるようにします。

#include <wiringPi.h>

次に、wiringPiSetupGpio()関数を呼び出し、GPIOを事前にセットアップしておきます。

    // Initialize WiringPi
    if(wiringPiSetupGpio() == -1) return 1;

使用するピンを出力用に設定します。4つのモーターを使用するためピン番号は事前に配列に入れてあるため、forループですべてのピンを出力に設定しています。

    for(int i = 0; i < 4; i++) {
        pinMode(vref[i], OUTPUT);
        pinMode(in1[i], OUTPUT);
        pinMode(in2[i], OUTPUT);
    }

また、ピン番号は「gpio readall」コマンドにて確認できます。

digitalWrite()関数により、目的のGPIOを0(LOW)または1(HIGH)に設定することが可能です。
このプログラムでは、IN1またはIN2を1(HIGH)に設定しています。
また、モータードライバのVrefは1(HIGH)にします。
これにより、モーターへの供給電圧は最大に設定されます。

    digitalWrite(in1[motor], vin1);
    digitalWrite(in2[motor], vin2);
    digitalWrite(vref[motor], 1);

コンパイルと実行

それではコンパイル及び実行をしてみましょう¥。

cc -std=c99 -pthread -o gpiotest gpiotest.c -lwiringPi
sudo ./gpiotest

実行すると、各モーターが回転したあと、プログラムが終了すると思います。

次にモーターのGPIOに渡す値を変えて試してみましょう。例えば次の画像はすべてのモーターを同じ方向に回した時の例です。



これでラズパイにおけるGPIOの制御が可能となりました。次回はこのロボットを制御するROSプログラミングについて解説していきます。


ROSで始めるロボティクス(9) ー ROSを使ったステレオカメラキャリブレーション
ROSで始めるロボティクス(10) ー オムニホイールで全方向移動可能ロボットを作る 1
ROSで始めるロボティクス(11) ー オムニホイールで全方向移動可能ロボットを作る 2

参考文献:
詳解 OpenCV
140 180 PWM , RaspberryPI , ROS , RPi , Ubuntu , WiringPi , オムニホイール , コラム , ロボット

記載されている会社名、および商品名等は、各社の商標または登録商標です。

0 コメント:

コメントを投稿

Related Posts Plugin for WordPress, Blogger...