.. include:: /index.rst
:start-after: start_hello_message
:end-before: end_hello_message
.. _py_fun_fan:
4.7 スマートファン
=========================
**はじめに**
このプロジェクトでは、手動モードと自動モードの両方で動作する「スマートファン」を作成します。モーター、ボタン、サーミスタを組み合わせることで、ファンの風量を調整できるだけでなく、温度変化にも応答できるようになります。モーター制御、温度検知、GPIO の使い方を学ぶのに最適な実験です。
----------------------------------------------
**必要なもの**
このプロジェクトで必要なコンポーネントは以下のとおりです。
.. list-table::
:widths: 30 20
:header-rows: 1
* - COMPONENT INTRODUCTION
- PURCHASE LINK
* - :ref:`cpn_breadboard`
- |link_breadboard_buy|
* - :ref:`cpn_wires`
- |link_wires_buy|
* - :ref:`cpn_resistor`
- |link_resistor_buy|
* - :ref:`cpn_thermistor`
- |link_thermistor_buy|
* - :ref:`cpn_button`
- |link_button_buy|
* - :ref:`cpn_motor`
- |link_motor_buy|
* - :ref:`cpn_fusion_hat`
- \-
* - Raspberry Pi
- \-
----------------------------------------------
**回路図**
以下の回路図は、サーミスタ、ボタン、モータードライバー、およびモーターの接続方法を示しています。
.. image:: img/fzz/4.1.7_sch.png
:width: 100%
:align: center
----------------------------------------------
**配線図**
ブレッドボード上のレイアウトと配線接続は、以下の図を参照してください。
.. image:: img/fzz/4.1.7_bb.png
:width: 80%
:align: center
----------------------------------------------
**サンプルの実行**
このチュートリアルで使用するすべてのサンプルコードは ``ai-lab-kit`` ディレクトリに含まれています。
以下の手順に従ってサンプルを実行してください。
.. raw:: html
.. code-block:: shell
cd ~/ai-lab-kit/python/
sudo python3 4.7_SmartFan.py
----------------------------------------------
**コード**
以下は、このプロジェクトで使用する Python スクリプトです。
.. raw:: html
.. code-block:: python
#!/usr/bin/env python3
from fusion_hat.motor import Motor
from fusion_hat.pin import Pin, Mode, Pull
from fusion_hat.adc import ADC
from time import sleep, time
import math
BtnPin = Pin(22, mode=Mode.IN, pull=Pull.DOWN)
motor = Motor("M0")
thermistor = ADC("A3")
level = 0
currentTemp = None
markTemp = None
PRINT_INTERVAL = 1.0
_last_print = 0.0
button_event = False # flag: button was pressed
def temperature(samples=5, delay=0.01):
"""Read thermistor multiple times and return averaged Celsius (float) or None."""
vals = []
for _ in range(samples):
analogVal = thermistor.read()
Vr = 3.3 * float(analogVal) / 4095.0
if (3.3 - Vr) <= 0.1:
return None
Rt = 10000.0 * Vr / (3.3 - Vr)
tempK = 1.0 / (((math.log(Rt / 10000.0)) / 3950.0) + (1.0 / (273.15 + 25.0)))
vals.append(tempK - 273.15)
sleep(delay)
return sum(vals) / len(vals)
def motor_run(lv):
lv = max(0, min(4, lv))
motor.power(0 if lv == 0 else lv * 25)
return lv
def changeLevel():
"""Button press: cycle level 0~4 and set a flag for main loop to print."""
global level, button_event
level = (level + 1) % 5
button_event = True
BtnPin.when_activated = changeLevel
def main():
global level, currentTemp, markTemp, _last_print, button_event
markTemp = temperature()
while True:
currentTemp = temperature()
if currentTemp is None:
print("Sensor read failed. Please check the sensor.")
sleep(0.5)
continue
# Handle button event in main loop (stable timing)
if button_event:
button_event = False
markTemp = currentTemp
print(f"[Button] Level -> {level} | Temp: {currentTemp:.2f} °C | Mark: {markTemp:.2f} °C")
# Periodic temperature print
now = time()
if now - _last_print >= PRINT_INTERVAL:
if markTemp is None:
markTemp = currentTemp
print(f"Temp: {currentTemp:.2f} °C | Mark: {markTemp:.2f} °C | Level: {level}")
_last_print = now
# Auto adjust level based on ±5°C
if markTemp is None:
markTemp = currentTemp
if level != 0:
diff = currentTemp - markTemp
if diff <= -5:
level = max(0, level - 1)
markTemp = currentTemp
print(f"[Auto] Temp down -> Level {level} (Temp: {currentTemp:.2f} °C)")
elif diff >= 5:
level = min(4, level + 1)
markTemp = currentTemp
print(f"[Auto] Temp up -> Level {level} (Temp: {currentTemp:.2f} °C)")
level = motor_run(level)
sleep(0.5)
try:
main()
except KeyboardInterrupt:
print("\nExiting...")
finally:
motor.stop()
sleep(0.1)
この Python スクリプトは、モーター、ボタン、および温度センサーを組み合わせて、温度に応じて動作し、速度を調整できるファンシステムを作成します。実行すると、次のように動作します。
1. **温度の測定**: サーミスタを使用して現在の摂氏温度を読み取ります。
2. **手動での風量調整**:
- GPIO22 に接続されたボタンにより、ユーザーは 5 段階の風量レベル(0~4)を順番に切り替えることができます。
- ボタンを押すたびに風量レベルが 1 段階上がり、モーターは対応する速度で動作します。レベル 0 ではモーターが停止します。
3. **自動風量制御**: システムは温度変化に応じてモーター速度を自動調整します。
- 温度が 5°C 以上上昇すると、風量レベルが 1 段階上がります(最大レベル 4)。
- 温度が 5°C 以上低下すると、風量レベルが 1 段階下がります(最小レベル 0)。
4. **継続的な監視**: システムは温度を継続的に監視し、それに応じてファン速度を調整します。
5. **安全な終了**: ``Ctrl+C`` を押すと、モーターを停止し、スクリプトは安全に終了します。
----------------------------------------------
**コードの解説**
1. **温度の計算:**
.. code-block:: python
def temperature(samples=5, delay=0.01):
"""Read thermistor multiple times and return averaged Celsius (float) or None."""
vals = []
for _ in range(samples):
analogVal = thermistor.read()
Vr = 3.3 * float(analogVal) / 4095.0
if (3.3 - Vr) <= 0.1:
return None
Rt = 10000.0 * Vr / (3.3 - Vr)
tempK = 1.0 / (((math.log(Rt / 10000.0)) / 3950.0) + (1.0 / (273.15 + 25.0)))
vals.append(tempK - 273.15)
sleep(delay)
return sum(vals) / len(vals)
``temperature()`` 関数は、サーミスタのアナログ値を複数回読み取り、抵抗値へ変換し、数式を用いて対応する温度を計算します。
2. **モーター速度制御:**
.. code-block:: python
def motor_run(lv):
lv = max(0, min(4, lv))
motor.power(0 if lv == 0 else lv * 25)
return lv
``motor_run()`` 関数は、 ``level`` 変数に応じてモーター速度を調整します。速度は 0~4 の範囲に制限され、それに応じた出力が設定されます。
3. **手動での風量調整:**
.. code-block:: python
def changeLevel():
"""Button press: cycle level 0~4 and set a flag for main loop to print."""
global level, button_event
level = (level + 1) % 5
button_event = True
BtnPin.when_activated = changeLevel
``changeLevel()`` 関数は、ボタンが押されるたびに風量レベルを 0~4 の範囲で順番に切り替えます。
4. **自動での風量調整:**
.. code-block:: python
def main():
global level, currentTemp, markTemp, _last_print, button_event
markTemp = temperature()
while True:
currentTemp = temperature()
if currentTemp is None:
print("Sensor read failed. Please check the sensor.")
sleep(0.5)
continue
...
``main()`` 関数は温度を継続的に監視し、基準温度から 5°C 以上ずれた場合にファン速度を自動調整します。
----------------------------------------------
**トラブルシューティング**
1. **モーターが動作しない** :
- **原因** : 配線ミス、または電源不足。
- **対処方法** :
- モーターが M0 に接続されていることを確認してください。
- モーターの電源が必要電圧を満たしていることを確認してください。
2. **温度読み取りが正しくない**:
- **原因** : サーミスタの不具合。
- **対処方法**:
- サーミスタの配線を確認し、仕様範囲内で使用されていることを確認してください。
3. **ボタン入力が検出されない** :
- **原因** : ボタン配線または GPIO 設定の誤り。
- **対処方法** :
- ボタンが GPIO22 と GND に接続されていることを確認してください。
- ボタン単体で、押したときに回路が閉じるかどうかをテストしてください。
4. **風量レベルが自動で変わらない**:
- **原因** : 温度差の計算が正しくありません。
- **対処方法** : ``main()`` 関数内で ``currentTemp`` と ``markTemp`` が正しく更新されていることを確認してください。
----------------------------------------------
**拡張アイデア**
1. **過熱アラート**: 温度が危険なしきい値を超えたときに、ブザーや LED で警告を出します。
.. code-block:: python
if currentTemp > 50:
buzzer.on()
2. **スマートボタン機能**: ボタンの長押しで風量レベルを 0 にリセットしたり、自動/手動モードを切り替えたりできるようにします。
----------------------------------------------
**まとめ**
スマートファンのプロジェクトでは、手動制御と自動制御を 1 つのシステムに統合する方法を学べます。これは、センサー、モーター、ユーザー操作を組み合わせた、実用的で効率的な設計例です。さらに機能を追加して、自分だけの温度制御システムへ発展させてみてください。