その5-1.冷却ファンを接続してPWMでCPU温度に応じた回転数制御を行う(そして失敗した話)

Raspberry Pi 4は熱い!

界隈が熱い(らしい?)のは昔からの話。そうじゃないんです。Raspberry Pi、物理的に熱いのです。一応CPU冷却用に小型ファンを購入しましたが、常時フル稼働では騒音(実はそんなにしませんけど)が気になりますし、常時稼働を前提としたドラレコと考えた場合、ある程度の出力制御を行って電力消費を少しでも抑えたい所。
なので今回はPWMを使ってファンの制御を行う事にします。

まずは配線

以下のサイトさんを参考に配線します。

Raspberry Pi でPWM信号を使って5Vファンを制御する - Qiita

ただ今回はpigpioを使ったソフトウェア制御を行います。なのでピンはどこを利用しても良いので、今回は空く予定のGPIO4へ接続。

f:id:nekhbet:20200130234706j:plain

制御プログラムのコーディング

早速コーディングを開始。今回はpigpioのIFではなく、pigpiodのIFを使ってコーディングします。
CPUの温度取得方法は2通りありますが、今回は文字列操作の必要のない方法を使います。(やってもいいしポインタ使って脳汁出るソース書いたりして楽しかったですけど、処理の軽さも重視していくので大人しくわかりやすい方法で)
コマンド実行結果の標準出力を用いるので、C++のpopen関数を利用します。

#include <stdio.h>
#include <cstring>
#include <stdlib.h>
#include <unistd.h>
#include <pigpiod_if2.h>

#define FAN_GPIO			4	// FANコントロールGPIO番号
#define FAN_PWM_DUTY_MIN	20	// PWM Duty最小値
#define FAN_PWM_DUTY_MAX	100	// PWM Duty最大値
#define FAN_PWM_FREQUENCY	10	// PWM周波数値
#define CPU_THERMAL_MIN		40	// ファン稼働CPU最低温度
#define CPU_THERMAL_MAX		80	// ファン稼働CPU最高温度

int main() {
	// pigpioへ接続
	int pi = pigpio_start(NULL, NULL);
	if (pi < 1) {
		printf("%d\n", pi);
		return 1;
	}

	// GPIO設定
	set_mode(pi, FAN_GPIO, PI_OUTPUT);
	set_PWM_range(pi, FAN_GPIO, FAN_PWM_DUTY_MAX);
	set_PWM_frequency(pi, FAN_GPIO, FAN_PWM_FREQUENCY);

	// CPU温度取得用変数
	const char* cmd = "cat /sys/class/thermal/thermal_zone0/temp";
	FILE* fp;
	char buf[1024];
	memset(buf, 0, sizeof(buf));

	// duty算出用設定値
	int pwm_duty_range = FAN_PWM_DUTY_MAX - FAN_PWM_DUTY_MIN;
	int cpu_thermal_range = CPU_THERMAL_MAX - CPU_THERMAL_MIN;

	while(1) {
		// CPU温度取得
		int thermal = 0;
		fp = popen(cmd,"r");
		if (fp != NULL) {
			fgets(buf, sizeof(buf), fp);
			thermal = atoi(buf) / 1000;
			pclose(fp);

			// Duty値算出
			int duty = 0;
			if (thermal > CPU_THERMAL_MAX) {
				// MAX以上なら100固定
				duty = FAN_PWM_DUTY_MAX;
			} else if (thermal > CPU_THERMAL_MIN) {
				// MINより上なら温度とduty値を比例させる
				duty = (CPU_THERMAL_MAX - thermal) / cpu_thermal_range * pwm_duty_range + FAN_PWM_DUTY_MIN;
			}
	
			// Duty値に変更があれば変更
			if (get_PWM_dutycycle(pi, FAN_GPIO) != duty) {
				set_PWM_dutycycle(pi, FAN_GPIO, duty);
			}
		}

		// 次のループ開始まで1秒待機
		time_sleep(1);
	}

	// pigpioへの接続終了
	pigpio_stop(pi);
	return 0;
}

これで動くはず…がなぜかpigpio_startで0が返ってきました。なぜ…
明日は不具合の原因究明と、バックグラウンド実行の設定を…行えたらいいですね。ちょっとこれは問題が面倒な気配…