DreamerDreamのブログ

夢想家の夢です。〜揚げたてのモヤっとしたものをラフレシアと共に〜

RaspberryPiでCPUファンの回転数を制御する

電圧のアナログ的な制御をデジタルで表現するために高速でON-OFFの切り換えをします。このような制御方法を「PWM制御」と言います。

今回はそのPWM制御をするという話で、ラズベリーパイの夏対策としてもファン制御はおさえておきたい項目でしょう。

 

RaspberryPiをしばらく使っているとWi-Fiが不安定で繋がらなくなることがしばしば発生しました。

どうやらWi-FiドングルからUSB端子を介して本体が熱くなっている様子です。

 

調べてみると、が原因で動作不良になることは報告がよくあり、特にケースに入れた状態での長時間稼働には適していないとの情報がありました。

熱を下げるにはヒートシンクを付けるかファンによる強制冷却しかありません。

やはり一番簡単なのはヒートシンクです。なにより安い。


 

逆に、冷却ファンはお高い。

と、思ったが!?ヒートシンクより安いファンも!?なんと300いえーん♪

12Vだけど5Vでも低回転で回るので大丈夫。最大130mA消費するので電源には注意です!


 

当然、ヒートシンクよりファンの方が効率良く冷却してくれますが、その分ホコリが貯まりやすいことや、電流がファンに奪われてしまう、また煩いという欠点もあります。

  

なので必要な時に必要な風量だけ送風してくれるようPWM制御を目指す事にしました。

 

== 動作概要 ==

  1. 以前に作ったcpu_temp.pyを利用してCPUの温度を取得
  2. 取得した温度を元にDuty比を決める
  3. PWM出力

以上を30秒毎に繰り返す。これだけです。

 

以前に作ったcpu_temp.pyは

dreamerdream.hateblo.jp

 

 

周波数は50Hz、Dutyはデフォルト5で出力。

※Dutyは100%だとずーっとスイッチ入れっぱなし、0%だとずーっと切りっぱなし、50%だとONとOFFが半々という、ON-OFFのONの時間比率です。

 

本当は周波数もkHzとか高い値を設定したかったのだけれど、どうやらソフトウェアPWM制御の限界があるようなのでコイル鳴りが気にならない程度の値に妥協設定しました。。

スタート時にファンが回らなかったら困るので起動時にはDuty100%で1秒間出力させています。 

 

-- gpio_fan_controld.py --

#!/usr/bin/python

 

import RPi.GPIO as GPIO

import time

import sys

import os

import cpu_temp

 

FAN = 18     #gpio_port 18

Hz = 50.0

DUTY = 5.0

 

top = 100.0 #Duty上限

bottom = 5.0 #Duty下限

height = 50.0 #最高温度

low = 30.0 #最低温度

 

def init():

        GPIO.setmode(GPIO.BCM)

        GPIO.setup(FAN, GPIO.OUT)

       

def end():

        GPIO.cleanup()

 

def get_temp():

        return float(cpu_temp.get_temp())

 

def get_duty(tmp = low):

        rs = 5.0

        if(height < tmp ):

                rs = top

        elif(tmp < low):

                rs = bottom

        else:

                rs = bottom + ( ( top - bottom ) / (height - low ) ) * (tmp - low)

        return rs

 

def pwm():

        time.sleep(1.0)

        init()

        p = GPIO.PWM(FAN,Hz)

        p.start(100)

        time.sleep(1.0)

        p.ChangeFrequency(Hz)

        p.ChangeDutyCycle(DUTY)          

        while 1:

                time.sleep(30)

                temp = get_temp()

                duty = get_duty(temp)

                p.ChangeDutyCycle(duty)

        p.stop()

        end()

 

def fork():

        pid = os.fork()

        if pid > 0:

                f = open('/var/run/gpio_fan_controld.pid','w')

                f.write(str(pid)+" ")

                f.close()

                sys.exit()

        if pid == 0:

                pwm()

 

if __name__=='__main__':        # if script

        fork()

 

 

 これをデーモンで動かすだけです。

 

このプログラムによりラズパイのGPIO18ピンにCPU温度に応じたDuty比のPWM信号が来るので、その信号を受けてファンを回転させる電子回路が必要になります。(電流不足になるのでラズパイのGPIOにそのままファン繋いだらダメですよ!)

 

今回、回路に利用したのは電子工作界隈では超有名なトランジスタ2sc1815

ベース抵抗は別に要らない(ラズパイ内のインピーダンスが高いから)という先輩のアドバイスを信じて単純な回路に構成しました。(心配なら100Ωぐらい付けておきましょう)

 

  • ベースにGPIO18ピンをダイレクト接続(3.3V)(通常は間に1kΩほどの抵抗は入れるが内部抵抗に頼って省略)
  • コレクタにファンのマイナス端子をダイレクト接続
  • エミッタはGND接続
  • ファンの+端子を電源の+(5V)に接続

f:id:DreamerDream:20151225135926j:plain

2SC1815は一個5円程度でリーズナブルです。

[商品価格に関しましては、リンクが作成された時点と現時点で情報が変更されている場合がございます。]

Kaito7744(10個) NPNトランジスタ 2SC1815GR
価格:50円(税込、送料別) (2016/12/19時点)


 

結構単じゃんな回路だけど、こんなんで結構キレイに制御出来ています。

これでCPU温度40℃を超える事は稀になりました。

 

<オマケ>

今回、ラズパイのソフトウェアPWMのON時間比率(Duty)を利用して電圧を制御して、ファン(ブラシレスモーター)の回転数を制御しました。 

PWMの周波数(Hz)を利用すればステッピングモーターの制御も可能になります↓

dreamerdream.hateblo.jp

 

 

 <参考記事>

dreamerdream.hateblo.jp

 

kampa.me