Записная книжка разработчика

Мои проекты

Raspberry Pi и контроль температуры

| Comments

Я уже писал про самодельную "Time Capsule" на базе Raspberry Pi. Она работает хорошо, если не считать проблемы с перегревом. В корпусе устройства установлен вентилятор, но он издаёт при работе существенный шум.

Итак, я решил подключить к RPi термодатчик и сделать автоматическое управление вентилятором.

Далее под катом.

Схемотехнически тут всё очень просто: термодатчик Analog Devices ADT7301 с интерфейсом SPI, вентилятор 40х40 мм, подключенный через транзисторный ключ к выходу PWM.

Плата с термодатчиком.

Датчик приклеен к радиатору источника питания (самая горячая точка в устройстве).

Использование PWM позволяет включать вентилятор не на полные обороты, что делает его очень тихим. Управление вентилятором осуществляет скрипт на Python.

Перед тем, как запустить скрипт, нужно поставить библиотеки для доступа к SPI и PWM.

py-spidev: библиотека для SPI

Wiring-Pi: библиотека для доступа к GPIO и PWM.

Для получения доступа к SPI нужно отредактировать файл /etc/modprobe.d/raspi-blacklist.conf.

В нём находятся такие строки:

blacklist spi -bcm2708

blacklist i2c -bcm2708

Эти строки закрывают доступ к spi и i2c соответственно. Нужно закомментировать строку для spi:

#blacklist spi -bcm2708

и перезапускаем систему: sudo reboot.

Управление вентилятором ступенчатое: есть два порога включения вентилятора, на 50% и на 100%. Есть небольшая тонкость: если подать на выключенный вентилятор сигнал PWM c 50% -м заполнением, он просто не раскрутится: не хватит подаваемой мощности для пуска двигателя. Поэтому на двигатель подаётся сначала кратковременный импульс со 100% заполнением, которого хватает для пуска мотора.

В принципе, всё работает, однако хочется ещё и визуализировать данные температуры и оборотов вентилятора. Для этого были поставлены библиотеки Numpy и Matplotlib. Библиотека Matplotlib позволяет строить любые типы графиков, доступных в Matlab (то есть просто любые, в том числе 3D). Но тут же выяснилась и оборотная сторона: эти библиотеки очень тяжелые для RPi. Формирование картинки размером 800х600 с 2-d графиком занимает до 2-3 секунд (!), при частоте опроса датчика 1 раз в 5 с загрузка процессора составляет почти 100%, и достигает момента, когда RPi перестает откликаться на мышь и клавиатуру.

Пример получаемого графика температуры приведен в начале поста.

Исходный тескт скрипта приведен здесь:

import spidev	#for spi
import wiringpi #for pwm
import time
from pylab import * #for chart
import matplotlib.pyplot as plt

tempTreshold1On = 50.0
tempTreshold1Off = 47.0
tempTreshold2On = 55.0
tempTreshold2Off = 52.0

speed0 = 0     # off
speed1 = 512   # 50% speed
speed2 = 1024  # 100% speed

#--------------------------------
#import 

# spi init
spi = spidev.SpiDev()
spi.open(0, 0)
# pwm init
wiringpi.wiringPiSetupGpio()
wiringpi.pinMode(18, 2)
wiringpi.pwmWrite(18, 1024)

n = 0 #current quantity of point in a chart
temp_points = [] #list of temperature points
speed_points = [] #list of fan speed points

speed = speed0
try:
	while True:
		# get 3 temperature values
		resp = spi.xfer2([0, 0])
		temp1 = resp[0] * 8 + resp[1]/32.0
		time.sleep(0.1)
		resp = spi.xfer2([0, 0])
		temp2 = resp[0] * 8 + resp[1]/32.0
		time.sleep(0.1)
		resp = spi.xfer2([0, 0])
		temp3 = resp[0] * 8 + resp[1]/32.0
		#----------------------
		#get the middle point of three values
		if ((temp1 >= temp2) and (temp1 = temp3)):
			temp = temp1
		elif ((temp2 >= temp1) and (temp2 = temp3)):
			temp = temp2
		else:
			temp = temp3
		#-------------------
		#find the current speed
		if temp < tempTreshold1Off:
			speed = speed0
		if (temp > tempTreshold1Off) and (temp < tempTreshold1On):
			if speed == speed2:
				speed = speed1
		if (temp > tempTreshold1On) and (temp < tempTreshold2Off):
			if speed == speed0:
				wiringpi.pwmWrite(18, 1024) #turn on a motor at max speed
				time.sleep(0.5)
			speed = speed1
		if (temp > tempTreshold2Off) and (temp < tempTreshold2On):
			if speed == speed0:
				wiringpi.pwmWrite(18, 1024) #turn on a motor at max speed
				time.sleep(0.5)
				speed = speed1
		if temp > tempTreshold2On:
			speed = speed2
		#-----------------------------
		# set the motor speed
		wiringpi.pwmWrite(18, speed)

		print temp1, temp2, temp3, "temp =", temp, speed
		# -----------------------------
		# draw a chart
		MAX_POINT = 12 # max quantity of point in the chart
		if n < MAX_POINT:
			n = n + 1
		else:
			temp_points.pop(0) #remove the first point
			speed_points.pop(0) #remove the first point
		temp_points.append(temp)
		speed_points.append(speed * 100.0 / 1024.0) #fan speed in percents

		print temp_points

		fig, host = plt.subplots()

		par1 = host.twinx()
		t = arange((n - 1) * -5.0, 5.0, 5)

		print t

		p1, = host.plot(t, temp_points, "-b")
		p2, = par1.step(t, speed_points, "-r", where = "post")

		host.set_xlim(-60, 0)
		host.set_ylim(25, 75)
		par1.set_ylim(-10, 110)

		host.set_xlabel("Time, min")
		host.set_ylabel("Temperature, C")
		par1.set_ylabel("Speed, %")

		host.yaxis.label.set_color(p1.get_color())
		par1.yaxis.label.set_color(p2.get_color())

		host.grid()
		#host.text('temp = {}' .format(temp))
		savefig("temp.png")
		#show()

		time.sleep(5 * 60)  # period = 5 min
	#end while

except KeyboardInterrupt:
	spi.close()
#end try

Скрипт нужно запускать командой sudo python spi.py

Некоторые пояснения к скрипту:
Чтение термодатчика происходит 3 раза, после этого выбирается среднее значение (не среднее арифметическое, а значение, лежащее между двумя другими). Это позволяет отфильтровать случайные выбросы показаний датчика.

Порог выключения вентилятора ниже порога включения на 3 градуса, то есть функция включения вентилятора имеет некоторый гистерезис, это позволяет избежать частых включений и выключений двигателя (кстати, на графике вверху видно, что двигатель включается и выключается периодически, чтобы этого не происходило, нужно изменить пороговые значения).
При включении двигателя на 50% мощности из выключенного состояния он кратковременно включается на полную мощность, причины поясняются выше.

В итоге я оставил в устройстве простой вариант скрипта, без визуализации. Можно попробовать другую библиотеку, полегче, но есть и другой способ. В настоящее время существуют облачные сервисы логгинга данных с датчиков, например, SensorCloud. У сервиса есть документированное API, позволяющее отправлять данные по протоколу https. Если объем данных не превышает 3 млн. точек в месяц, сервисом можно пользоваться бесплатно.

Но это уже другая история.