1.LEDの制御

注意:配線の間違いがないことを確認してからラズベリーパイとブレッドボードをつなぐこと.突然電源が落ちた場合は,すぐにラズベリーパイの電源を切り,ブレッドボードを外すこと.ショートすると壊れて2度と起動しなくなることもあります.

各ピンの機能は以下の通り

raspberry_pi_GPIO

抵抗の計算

$使うべき抵抗=\frac{電源電圧-順方向電圧降下}{順方向電流} $

順方向電圧降下(Vf)

順方向電流(If)

例題:電源電圧:5[V],If=5[mA],Vf=3.1[V]のとき,抵抗Rは何[Ω]を使うのが適切か?

$R = \frac{5-3.1}{0.005} = 380[Ω]$

1.1 LEDを1個制御する場合

LED1

In [ ]:
import RPi.GPIO as GPIO
import time

#初期設定
GPIO.setmode(GPIO.BCM)
GPIO.setup(26, GPIO.OUT)#26番のピンを出力モードで使う

GPIO.output(26,True)#LEDをONにする
time.sleep(2)#2秒間待つ
GPIO.output(26,False)#LEDをOFFにする
time.sleep(2)#2秒間待つ

print("終了")
GPIO.cleanup()

解説

In [ ]:
GPIO.setmode(GPIO.BCM)

だと、ピン番号ではなく役割に記載されたGPIOの数字で指定することになる.

In [ ]:
GPIO.setmode(GPIO.BOARD)

だと、GPIOピンを選択するにはピン番号(左下から右上までの連番)で指定することになる.

1.2 同じ処理を複数回繰り返す場合

In [ ]:
import RPi.GPIO as GPIO
import time

#初期設定
GPIO.setmode(GPIO.BCM)
GPIO.setup(26, GPIO.OUT)#26番のピンを出力モードで使う

#繰り返し
for t in range(0,10): #繰り返したい数を指定する.
    GPIO.output(26,True)#LEDをONにする
    time.sleep(2)#2秒間待つ
    GPIO.output(26,False)#LEDをOFFにする
    time.sleep(2)#2秒間待つ
print("おしまい")
GPIO.cleanup()

もし、途中で強制的に処理を停止したい場合は、「Ctr+C」で停止させることができる.

1.3 複数のLEDを制御する場合

LED2

In [ ]:
#LED2個点灯させる場合
import RPi.GPIO as GPIO
import time

#初期設定
GPIO.setmode(GPIO.BCM)
GPIO.setup(26, GPIO.OUT)#26番のピンを出力モードで使う
GPIO.setup(19, GPIO.OUT)#19番のピンを出力モードで使う

GPIO.output(26,True)#26番のLEDをONにする
GPIO.output(19,False)#19番のLEDをONにする
time.sleep(2)#2秒間待つ
GPIO.output(26,False)#26番のLEDをOFFにする
GPIO.output(19,True)#19番のLEDをOFFにする
time.sleep(2)#2秒間待つ
    
GPIO.cleanup()

たくさんのLEDを制御する場合も基本は同じ.

(1)使用するピンのを出力モードで使うことを宣言する (GPIO.setup(使うピン番号, GPIO.OUT))

(2)ONにしたいなら,GPIO.output(26,True),OFFにしたいなら Falseと書く.

(3)最後に GPIO.cleanup()で処理を終える.

練習問題1

ここまでの知識を使って,イルミネーションを作ってみる!

直列接続、並列接続を組み合わせて、たくさんのLEDを制御してみる.

抵抗の計算も忘れずに!

2.AD変換

ラズベリーパイはデジタル信号しか扱うことができない.しかし,距離や速度,明るさなどの計測を行うには,アナログ信号を取り扱う必要がある.

ここでは,10bit 8ch ADコンバータ「MCP3008」を使用してAD変換を行う.

AD

例えばフォトセンサを使う場合なら以下のように配線してCh1~8のいずれかに接続.

sensor

2.1 AD変換 基本

In [ ]:
#AD変換 基本
import spidev#SPI通信を使用するためのライブラリ
import time 

spi = spidev.SpiDev() #SPI通信の設定
# spi.open(bus,device)
spi.open(0,0)
spi.max_speed_hz = 1000000

def readAdc(channel):#センサの測定値を変換する関数
    adc = spi.xfer2([1,(8+channel)<<4,0])
    # print(adc)
    data = ((adc[1]&3) << 8) + adc[2]
    return data

if __name__ == '__main__': # 1ch は0, ..., 8chは 7 と書くこと.
        ch = 0 #この場合は1chの信号をAD変換して値を表示
        
        for t in range(0,100): #100回文値を表示する
            data1 = readAdc(ch) #chの値を上記の関数で数値に変換
            print(data1) #値の表示
            time.sleep(0.5) #0.5秒に1回データを計測する.(サンプリング)

「def readAdc(channel)」の部分は関数といい,引数(括弧のなかに入れる変数のこと)を入力すると,「return X」のX(返り値)の値を計算して出力してくれる.同じ処理を何度も繰り返す場合などは,その処理を関数化しておくとプログラムも見やすくなり,エラーも少なくなる.

この場合は,1~8chすべて使用しているときに8回センサの値を変換するプログラムを書かなくていいので関数化している.

2.2 複数のチャンネルの値を表示する場合

In [ ]:
import spidev#SPI通信を使用するためのライブラリ
import time 

spi = spidev.SpiDev()#SPI通信の設定
# spi.open(bus,device)
spi.open(0,0)


def readAdc(channel): #センサの測定値を変換する関数
    adc = spi.xfer2([1,(8+channel)<<4,0])
    # print(adc)
    data = ((adc[1]&3) << 8) + adc[2]
    return data

if __name__ == '__main__': # 1ch は0, ..., 8chは 7 と書くこと
        for t in range(0,50):
            data1 = readAdc(0) # 1chの値を変換
            data2 = readAdc(1) # 2chの値を変換
            data3 = readAdc(2) # 3chの値を変換
            print(data1,data2,data3) #1~3chの値を表示
            time.sleep(0.5) #サンプリング

2.3 センサの値に応じて,LEDのON,OFFを切り替える

センサの値が一定値以上だとLEDが点灯し,一定値以下だと消える.

In [ ]:
#AD変換 基本+LED制御
import spidev
import RPi.GPIO as GPIO
import time 

GPIO.setmode(GPIO.BCM)
GPIO.setup(26, GPIO.OUT)

spi = spidev.SpiDev()
# spi.open(bus,device)
spi.open(0,0)


def readAdc(channel):
    adc = spi.xfer2([1,(8+channel)<<4,0])
    # print(adc)
    data = ((adc[1]&3) << 8) + adc[2]
    return data

if __name__ == '__main__': # 1ch -> 0, ..., 8ch -> 7
        ch = 0
        
        for t in range(0,100):
            data1 = readAdc(ch)
            print(data1)
            time.sleep(0.1)
            
            if data1 > 300: #センサの値が300以上であるかどうかを判断
                GPIO.output(26,True)#LEDをONにする
            else:
                GPIO.output(26,False)#LEDをONにする
                
        GPIO.cleanup()

練習問題2

センサの値に応じて3種類の点灯パターンをするプログラムを考える.練習問題1と組み合わせてもOK.

3.モータの制御

DCモータを制御するプログラム.ここでは,モータドライバ ta7291pを使用.接続方法は以下の通り.

番号 記号 役割
1  GND グラウンド
2  OUT1 モータにつなぐ
3  NC 使わない
4  Vref PWMを入力して回転数を制御
5  IN1 IN2み合わせて,正転,逆転,ストップ,ブレーキを制御
6  IN2 IN1と組み合わせて,正転,逆転,ストップ,ブレーキを制御
7  Vcc モータドライバ用電源(ラズベリーパイから取る) 5V
8  Vs モータ用電源 0~20V
9  NC 使わない
10  OUT2 モータにつなぐ

motor_driver

3.1 モータの制御(ON,OFFのみ PWM未使用)

In [ ]:
import RPi.GPIO as GPIO
import time 

GPIO.setmode(GPIO.BCM)
GPIO.setup(21, GPIO.OUT)#IN1に接続
GPIO.setup(20, GPIO.OUT)#IN2に接続
GPIO.setup(12, GPIO.OUT)#Vrefに接続

#正転
GPIO.output(21,True)
GPIO.output(20,False)
GPIO.output(12,True)

time.sleep(2)

#ブレーキ
GPIO.output(21,True)
GPIO.output(20,True)
GPIO.output(12,False)

print("おしまい")
GPIO.cleanup()

この場合はPWMを使わずにVrefと接続した12番をTrueにして正転させたため,デューティ比100%と同じ.つまり,全力でONとOFFしかできない.

3.2 PWMを使用する場合(速度を調整できる)

In [ ]:
import RPi.GPIO as GPIO
import time 

GPIO.setmode(GPIO.BCM)
GPIO.setup(21, GPIO.OUT)#IN1に接続
GPIO.setup(20, GPIO.OUT)#IN2に接続
GPIO.setup(18, GPIO.OUT)#Vrefに接続

p18 = GPIO.PWM(18,60)#PWMを使用するための宣言(60については気にしなくていい)
p18.start(0)#PWMをつかえる状態にする

#正転
GPIO.output(21,True)
GPIO.output(20,False)

p18.ChangeDutyCycle(0)#デューティ比0%
print("0%")
time.sleep(2)
p18.ChangeDutyCycle(25)#デューティ比25%
print("25%")
time.sleep(2)
p18.ChangeDutyCycle(50)#デューティ比50%
print("50%")
time.sleep(2)
p18.ChangeDutyCycle(75)#デューティ比75%
print("75%")
time.sleep(2)
p18.ChangeDutyCycle(100)#デューティ比100%
print("100%")
time.sleep(2)

print("おしまい")
GPIO.cleanup()

2017年4月では,すべてのピンがPWMに対応しているわけではない.12と18番は対応しているので使用する際はこの2つを使う.

もっとたくさん必要にな場合は,ICを使うしかない.(例えば,TLC5940など)

PWMについてはメカトロニクス演習で勉強して.

練習問題3

モータドライバを2つ使って,2つのモータを制御してみる.配線が複雑になるので,ショートに注意!

4. ライントレースカーの基礎

ここではセンサを1つ使って,ON・OFF制御でライントレースするプログラムを紹介する.

In [ ]:
#ライントレースカー サンプル
#更新日:2017/5/16
#作成者:栁澤

#基本形
#右左折のみで進む


import RPi.GPIO as GPIO
import spidev
import time

##モータ制御関連###################################
m_right1 = 16 #右モータ方向制御用pin1
m_right2 = 20 #右モータ方向制御用pin2
m_right_pwm = 12 #右モータ速度制御用

m_left1 = 26  #左モータ方向制御用pin1
m_left2 = 19  #左モータ方向制御用pin2
m_left_pwm = 18 #左モータ速度制御用

#GPIOの設定
GPIO.setmode(GPIO.BCM)
GPIO.setup(m_right1, GPIO.OUT)
GPIO.setup(m_right2, GPIO.OUT)
GPIO.setup(m_right_pwm, GPIO.OUT)
right_pwm = GPIO.PWM(m_right_pwm,60)
right_pwm.start(0)

GPIO.setup(m_left1, GPIO.OUT)
GPIO.setup(m_left2, GPIO.OUT)
GPIO.setup(m_left_pwm, GPIO.OUT) 
left_pwm = GPIO.PWM(m_left_pwm,60)
left_pwm.start(0)


dt = 0 #サンプリングの設定(必要に応じて)
thre_v = 300 #閾値(白と黒の境目を決める)
################################################

##センサ関連(AD変換,SPI通信#######################
spi = spidev.SpiDev()
# spi.open(bus,device)
spi.open(0,0)

def readAdc(channel):
    adc = spi.xfer2([1,(8+channel)<<4,0])
    # print(adc)
    data = ((adc[1]&3) << 8) + adc[2]
    return data
################################################

##メインルーチン################################
while(1):
    ##計測(今回は真ん中しか使っていない)
    #data1 = readAdc(0)#LEFT
    data2 = readAdc(1)#CENTER
    #data3 = readAdc(2)#RIGHT
    #print(data1, data2, data3)

     ##ライントレースロボットの判断部分
    if data2 > thre_v: #left
        GPIO.output(m_left1,True)
        GPIO.output(m_left2,True)
        left_pwm.ChangeDutyCycle(25)

        GPIO.output(m_right1,False)
        GPIO.output(m_right2,True)
        right_pwm.ChangeDutyCycle(25)

        time.sleep(dt)
        #print("left")

    else:
        GPIO.output(m_left1,True)
        GPIO.output(m_left2,False)
        left_pwm.ChangeDutyCycle(25)

        GPIO.output(m_right1,True)
        GPIO.output(m_right2,True)
        right_pwm.ChangeDutyCycle(25)
        
        time.sleep(dt)
        #print("right")
################################################

GPIO.cleanup()

特にゴール条件を設定していないので注意.Ctr+Cで強制終了させてください.