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で出力

本当は周波数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信号が来ているのでそれを受けてファンを回転させる回路が必要。

 

回路に利用したのは超有名なトランジスタ2sc1815。ベース抵抗は別に要らない(Pi内インピーダンス任せ)という先輩のアドバイスを信じて単純な回路に構成。

 

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

f:id:DreamerDream:20151225135926j:plain

トランジスタは電子工作ではおなじみの2sc1815

一個5円程度でリーズナブル。

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

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


 

 こんなんで結構キレイに制御出来ている。これでCPU温度40℃を超える事は稀になった。

 

 

dreamerdream.hateblo.jp