This is a struggle record for using the "TSL2561 Illuminance Sensor Module (Manufacturer Part Number: TSL2561)" manufactured by Strawberry Linux on the Rasberry pi 3. There are some articles about sensors using the TSL2561 chip, but they didn't work or were python3. So I tried trial and error with python2.
By the way ... I'm new to python for half a month, new to electronic work, and have little knowledge ... I hope it will be helpful while keeping that in mind.
For the time being, the summary of the parts necessary for use is here.
It is necessary to solder the pin header to put the delivered sensor on the breadboard. After that, wire while looking at the included paper. Raspi's GPIO pin configuration is not difficult, as it will come up as soon as you search.
Sensor 1pin (GND)-> Raspi 6th pin Sensor 2pin (SDA)-> Raspi pin 3 Sensor 3pin (SCL)-> Raspi 5th pin Sensor 4pin (VDD)-> Raspi pin 1
It is like this.
I'm not sure what I2C is. However, according to the wiki, it seems to be a standard for connecting various devices with a chain like scsi. Anyway, enable it for use with raspbian.
Open the OS config menu from the ssh console and set.
$ sudo raspi-config
Select the menu in the order of "9 Advenced Options"-> "A7 I2C". You will be asked "Would you like the ARM I2C interface to be enabled?", So select yes. You will be asked "Would you like the I2C kernel module to be loaded by default?", So select yes.
Then edit /boot/config.txt as follows:
$ sudo vi /boot/config.txt
...Added the following contents
dtparam=i2c_arm=on
In addition, edit / etc / modules as follows.
$ sudo vi /etc/modules
...Added the following contents
snd-bcm2835
i2c-dev
After completing the settings, restart Raspy. Make sure the kernel module is loaded with the lsmod command after a reboot.
$ lsmod
...
i2c_dev 6709 0
snd_bcm2835 21342 0
...
Install the commands to use I2C and the python library (maybe).
$ sudo apt-get install i2c-tools python-smbus
When the wiring is completed and the tools are installed, check with the command whether the sensor module is recognized.
$ sudo i2cdetect -y 1
0 1 2 3 4 5 6 7 8 9 a b c d e f
00: -- -- -- -- -- -- -- -- -- -- -- -- --
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
30: -- -- -- -- -- -- -- -- -- 39 -- -- -- -- -- --
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
70: -- -- -- -- -- -- -- --
It seems to be recognized at address 0x39.
... so far, it's been fine.
First of all, when I tried it with reference to this article, although the value came out, it did not seem to be linked to light and dark. http://qiita.com/masato/items/1dd5bed82b19477b45d8
So, when I investigated further, I arrived at this article, but it is python3. http://shimobayashi.hatenablog.com/entry/2015/07/27/001708
Hmmm, can't I access it with the default python2?
If you read the above article and the source of git, it seems that you should use the smbus library to access the I2C device from python. However, I'm not sure how to use it, so I'll try it by trial and error.
According to the attachment from Strawberry Linux
The sensor starts operation by writing 0x03 to the internal register 0xA0. When 2 bytes are read from the internal address 0xAC, this becomes the raw data of the brightness of the visible light sensor (16 bits, the lower byte comes first). When 2 bytes are read from the internal address 0xAE, this becomes the raw data of the infrared sensor (16 bits, the lower byte comes first).
There is. ... Hmm Nanno Kotcha.
Anyway, Raspi seems to recognize TSL2561 at 0x39, so I wondered if I should read or write 0xA0, 0xAC, 0xAE from there, but the problem is how to do it.
When I searched variously with smbus, I came across the following site. http://raspberrypi.stackexchange.com/questions/8469/meaning-of-cmd-param-in-write-i2c-block-data http://www.raspberry-projects.com/pi/programming-in-python/i2c-programming-in-python/using-the-i2c-interface-2
I'm not good at English, so I read diagonally around the sample source and try and error by intuition. As a result of various trials, it seems that you can read or write the specified internal address by doing the following.
bus = smbus.SMBus(1)
bus.write_i2c_block_data(0x39, 0xA0, [0x03])
bus.read_i2c_block_data(0x39, 0xAC ,2)
The first smbus.SMBus (1) is creating an object to access the bus, maybe. '1' seems to be the same as the 1 specified at the end of "sudo i2cdetect -y 1", and it seems to specify the X of the "i2c-X" file under / dev /.
Use the bus.read_i2c_block_data method to read the data.
bus.read_i2c_block_data (I2C address, internal address, number of data bytes to read)
Use the write_i2c_block_data method to write data.
write_i2c_block_data (I2C address, internal address, data array to write)
With this, when I wrote the sample source, some values like that came out. When you hold your hand over it, the value changes in response. I feel like I can go!
#!/usr/bin/python -u
# -*- coding: utf-8 -*-
import smbus
import time
bus = smbus.SMBus(1)
bus.write_i2c_block_data(0x39, 0x80, [0x03])
while True:
data = self.bus.read_i2c_block_data(self.address, 0xAC ,2)
raw = data[1] << 8 | data[0]
print "Ambient light: " + str(raw)
data = self.bus.read_i2c_block_data(self.address, 0xAE ,2)
raw = data[1] << 8 | data[0]
print "Infrared: " + str(raw)
time.sleep(1.0)
Since it seems that raw data can be obtained, we will try to calculate the illuminance (Lux). Again, according to the attachment from Strawberry Linux,
Please refer to the manufacturer's data sheet for an algorithm that converts the raw data of visible light and infrared sensors into illuminance (lux).
There is. Where is the manufacturer! As a result of various googles while thinking, the following URL seems to be a data sheet with a TAOS chip.
https://cdn-shop.adafruit.com/datasheets/TSL2561.pdf
Cool! !! (Hematemesis) Is it an English document, fight, fight, scared heart ~ .... I manage to read diagonally while asking myself what I am doing to GW. Then, on page 23, there was "Calculating Lux", and I found the formula that I saw in the git source.
I see, I understand the flow, so let's classify it.
#!/usr/bin/python -u
# -*- coding: utf-8 -*-
import smbus
import time
#From "TSL2561 Illuminance Sensor Module" by Strawberry Linux
#Class to acquire data by I2C (1)
# https://strawberry-linux.com/catalog/items?code=12561
# 2016-05-03 Boyaki Machine
class SL_TSL2561:
def __init__(self, address, channel):
self.address = address
self.channel = channel
self.bus = smbus.SMBus(self.channel)
self.bus.write_i2c_block_data(self.address, 0x80, [0x03])
time.sleep(0.5)
def getVisibleLightRawData(self):
data = self.bus.read_i2c_block_data(self.address, 0xAC ,2)
raw = data[1] << 8 | data[0] #16bit with lower byte first
return raw
def getInfraredRawData(self):
data = self.bus.read_i2c_block_data(self.address, 0xAE ,2)
raw = data[1] << 8 | data[0] #16bit with lower byte first
return raw
def getLux(self):
#Acquisition of raw sensor data
VLRD = getVisibleLightRawData()
IRRD = getInfraredRawData()
#Don't divide by zero
if (float(VLRD) == 0):
ratio = 9999
else:
ratio = (IRRD / float(VLRD))
#Lux calculation
if ((ratio >= 0) & (ratio <= 0.52)):
lux = (0.0315 * VLRD) - (0.0593 * VLRD * (ratio**1.4))
elif (ratio <= 0.65):
lux = (0.0229 * VLRD) - (0.0291 * IRRD)
elif (ratio <= 0.80):
lux = (0.0157 * VLRD) - (0.018 * IRRD)
elif (ratio <= 1.3):
lux = (0.00338 * VLRD) - (0.0026 * IRRD)
elif (ratio > 1.3):
lux = 0
return lux
if __name__ == "__main__":
sensor = SL_TSL2561(0x39,1)
while True:
print "Lux : " + str(sensor.getLux())
time.sleep(1.0)
It's pretty simple, but reading the git source makes it more complicated and long. What's the difference?
When reading the git source, Gain and Scale appear before the illuminance calculation. After investigating what the heck was, I found the description of "high gain (16 ×)" in the "Timing Register" on page 15 of the data sheet, and carefully reread this area.
Apparently, this sensor has a specification that expands the sensing range by combining "Gain" and "Integration Time". Does it mean that the sensitivity will be 16 times higher with Height Gain? Also, if the integration time is changed from the default 402ms to 101ms and 13.7ms, the integration time of the sensing value will be shortened, and the sensitivity will decrease (= the output value will decrease). Does it feel like the exposure time is getting shorter?
Based on this information, change Gain and Integration Time variously and see the output of raw data. First, it was found that when set to High Gain, a value of approximately 16 times was obtained. It was also found that when the Integration Time was set to 101ms and 13.7ms, the values of 101/402 and 13.7 / 402 were obtained.
For example, in Hyuga during May, in the default state (Gain is 1, Integration Time is 402ms), the output of visible light will be 65535 (maximum value of 16bit), and the correct value cannot be obtained. In such a case, it seems that the specification is to set the Integration Time short and obtain a valid value.
However, at the time of High Gain, if there was a certain amount of light (near the window during the day), there was a problem that the raw data of both visible light and infrared light was fixed at 5047, which could not be solved. It works fine in low light.
Anyway, it seems that you need to scale the raw data before doing the illuminance calculation because the output changes depending on the setting. What I didn't really understand here was which setting the calculation formula in the data sheet was based on. Looking at the git source, when it is Low Gain, the raw data is multiplied by 16. Write some sample code to get the actual measurement data and compare it with the following site.
http://detail.chiebukuro.yahoo.co.jp/qa/question_detail/q12117474762
As a result, I concluded that High Gain was the base. I wonder if it is written somewhere in the data sheet. .. ..
Rebuild the class based on trial and error. We have prepared a method that allows you to change Gain and Integration Time.
#!/usr/bin/python -u
# -*- coding: utf-8 -*-
import smbus
import time
#From "TSL2561 Illuminance Sensor Module" by Strawberry Linux
#Class to get data in I2C
# https://strawberry-linux.com/catalog/items?code=12561
# 2016-05-03 Boyaki Machine
class SL_TSL2561:
def __init__(self, address, channel):
self.address = address
self.channel = channel
self.bus = smbus.SMBus(self.channel)
self.gain = 0x00 # 0x00=normal, 0x10=×16
self.integrationTime = 0x02 # 0x02=402ms, 0x01=101ms, 0x00=13.7ms
self.scale = 1.0
#Initialization of sensor settings
self.setLowGain()
self.setIntegrationTime('default')
def powerOn(self):
self.bus.write_i2c_block_data(self.address, 0x80, [0x03])
time.sleep(0.5)
def powerOff(self):
self.bus.write_i2c_block_data(self.address, 0x80, [0x00])
#Set to High Gain(16 times more sensitive?)
def setHighGain(self):
#When set to High Gain, raw data may not be obtained properly.
#Investigation of the cause required(5047 Fixed value)
self.gain = 0x10
data = self.integrationTime | self.gain
self.bus.write_i2c_block_data(self.address, 0x81, [data])
self.calcScale()
# Low Gain(default)Set to
def setLowGain(self):
self.gain = 0x00
data = self.integrationTime | self.gain
self.bus.write_i2c_block_data(self.address, 0x81, [data])
self.calcScale()
#Setting the time to integrate (time for one sensing?)
# val = shor, middle, logn(default)
def setIntegrationTime(self, val):
if val=='short':
self.integrationTime = 0x00 # 13.7ms scale=0.034
elif val=='middle':
self.integrationTime = 0x01 # 101ms scale=0.252
else:
self.integrationTime = 0x02 # defaultVal 402ms scale=1.0
data = self.integrationTime | self.gain
self.bus.write_i2c_block_data(self.address, 0x81, [data])
self.calcScale()
def getVisibleLightRawData(self):
data = self.bus.read_i2c_block_data(self.address, 0xAC ,2)
raw = data[1] << 8 | data[0] #16bit with lower byte first
return raw
def getInfraredRawData(self):
data = self.bus.read_i2c_block_data(self.address, 0xAE ,2)
raw = data[1] << 8 | data[0] #16bit with lower byte first
return raw
def getRawData(self):
data = self.bus.read_i2c_block_data(self.address, 0xAC ,4)
VL = data[1] << 8 | data[0] #Visible light 16 bits, lower byte first
IR = data[3] << 8 | data[2] #Infrared 16bit, lower byte first
return (VL,IR)
def calcScale(self):
_scale = 1.0
#Scale by integrationTime
if self.integrationTime == 0x01: # middle
_scale = _scale / 0.252
elif self.integrationTime == 0x00: # short
_scale = _scale / 0.034
#Scale by gain
if self.gain == 0x00 : # gain 1
_scale = _scale * 16.0
self.scale = _scale
def getLux(self):
#Acquisition of raw sensor data
raw = self.getRawData()
#Implementation to output an error when 65535
if raw[0] == 65535 or raw[1] == 65535:
return "Range Over"
#Scale raw data with sensor settings
VLRD = raw[0] * self.scale
IRRD = raw[1] * self.scale
#Don't divide by zero
if (float(VLRD) == 0):
ratio = 9999
else:
ratio = (IRRD / float(VLRD))
#Lux calculation
if ((ratio >= 0) & (ratio <= 0.52)):
lux = (0.0315 * VLRD) - (0.0593 * VLRD * (ratio**1.4))
elif (ratio <= 0.65):
lux = (0.0229 * VLRD) - (0.0291 * IRRD)
elif (ratio <= 0.80):
lux = (0.0157 * VLRD) - (0.018 * IRRD)
elif (ratio <= 1.3):
lux = (0.00338 * VLRD) - (0.0026 * IRRD)
elif (ratio > 1.3):
lux = 0
return lux
if __name__ == "__main__":
sensor = SL_TSL2561(0x39,1)
sensor.powerOn()
# sensor.setHighGain()
sensor.setIntegrationTime('default')
while True:
print "Lux : " + str(sensor.getLux())
time.sleep(1.0)
By using the above class, you can get such a value. However, the problem of High Gain has not been solved. I can't confirm if the implementation is correct in the first place ...
Looking at the sample source of the data sheet, when accessing the internal address (Is it a register?), It is 0xAX or 0x8X. Looking at the specifications of "Register Set", only 0h to Fh are written. If you guess from the source whether it is 0xA or 0x8, I think that you are specifying the type of the value to be acquired, but I do not know the truth. No matter which address you specify, the same value will be obtained, so I suspect that python is converting it to good. Please let me know if anyone knows.
If you check the raw data value as appropriate and switch the Gain or Integration Time settings when the limit value is approached, you can seamlessly measure a wide range.
If its helpful then im happy.
Recommended Posts