Sensors - SamsungResearchUK-IoT-Meetup/multimode_sensor_platform GitHub Wiki

Sensors

This section describes the sensors being used within the system. Each sensor will have it's own section with example code and descriptions on how it works.

Tempearture and Humidity Sensor (HDC2080)

The HDC 2080 sensor documentation can be found here. There is no PIN configuration since this device is connected via I2C bus a 2 wire bus protocol. The driver for the HDC 2080 is adapted from the micropython code, it includes some helper functions, hardening and statistics.

hdc 2080 tile

HDC Setup

The HDC sensor contains a temperature sensor and a humidity sensor combined. It has address number 64 on the bus. The sensor is mounted via the tile header onto something like the DIP 28 or the DIP 68 i.e. it's modular and pluggable.

Testing The Driver

The driver for the sensor is here. The hdc2080_sensor.py file is really an enhancement to the basic micropython example code adding a few helper methods, some hardening and a few statistics. It allows you to create an object to get basic information from your Humidity and Temperature sensor. It provides methods for temperature, humidity, testing the sensor is ready and holding the max and min temperature values of values that are fetched from the board.

First Steps

The pyboard may have a power optimization feature enabled. You need to make sure this is disabled on the pyboard 'D' to get readings from the tile sensor. To do this type this command in the REPL before continuing with testing the sensors:

   >>>   machine.Pin.board.EN_3V3.value(1)

Creating HDC2080 Sensor

Once you have copied the file onto the board, you can create a HDC object:

/> rshell
/> repl
>>> import machine
>>> from hdc2080_sensor import HDC_Sensor
>>> i2c = machine.I2C('X')
>>> tempHumidity = HDC_Sensor(i2c)

Getting Statistics

To get statistics from the temperature and humidity sensor use methods max_temperature() and min_temperature() like this:

>>> tempHumidity.max_temperature()
0
>>> tempHumidity.min_temperature()
0

Detecting Current Temperature

The temperature and humidity sensor has two methods for detecting current temperature and humidity which are:

  • temperature()
  • humidity() The respond with the temperature in degrees centigrade and humidity in percentage concentration of water vapour present in the air. Examples are:
>>> tempHumidity.temperature()
23.456
>>> tempHumidity.humidity()
41.431

HDC2080 Object Attributes

The HDC2080 public Object Attributes can tell you the start time start_time of the HDC2080 object and used like this:

>>> tempHumidity.start_time
611145275

Checking HDC2080 Is Ready

The HDC2080 can be send a message to see if it's ready. Like a 'ping' in network terminanology. In other words it will return a 'True' response on the I2C bus if it's ready to recieve commands. To do this:

>>> tempHumidity.is_ready()
True

Errors From HDC2080

If the HDC2080 is not responding to messages, there is an electrical fault between the microcontroller and the tile sensor, or the firmware is not configured to use the I2C bus you will see an error generated on the repl like this:

>>> tempHumidity.is_ready()
The I2C bus is not responding to the I2C device address of: 64
Error value: [Errno 19] ENODEV
False
>>>
>>> tempHumidity.temperature()
The I2C bus is not responding to the I2C device address of: 64
Error value: [Errno 19] ENODEV
0

Notice that the sensor object is still handling API calls. In this case the temperature sensor reading responds with '0'. This is not the actual temperature or the temperature value on the tile. It's a default software value that is returned by the HDC Sensor object.

Light Level Sensor (OPT3001)

The OPT 3001 sensor documentation can be found here. There is no PIN configuration since this device is connected via I2C bus a 2 wire bus protocol. The driver for the OPT 3001 is adapted from the micropython code, it includes some helper functions, hardening and statistics.

You can find an image at the top of the page.

OPT Setup

The OPT sensor contains a light level sensor. It has address number 69 on the bus. The sensor is mounted via the tile header onto something like the DIP 28 or the DIP 68 i.e. it's modular and pluggable.

Testing The Driver

The driver for the sensor is here. The opt3001_sensor.py file is really an enhancement to the basic micropython example code adding a few helper methods, some hardening and a few statistics. It allows you to create an object to get basic information from your light level sensor. It provides methods for lux level, testing the sensor is ready and holding the max and min lux values of values that are fetched from the board.

Creating OPT3001 Sensor

Once you have copied the file onto the board, you can create a OPT object:

/> rshell
/> repl
>>> import machine
>>> from opt3001_sensor import OPT_Sensor
>>> i2c = machine.ID2C('X')
>>> opt = OPT_Sensor(i2c)

Getting Statistics

To get statistics from the temperature and humidity sensor use methods max_lux() and min_lux() like this:

>>> opt.max_lux()
4318.719
>>> opt.min_lux()
4.72

Detecting Current Light Levels

The light level sensor has a method for detecting current light levels which are:

  • lux() It responds with the light lux level. Examples are:
>>> opt.lux()
148.16
>>> opt.lux()
4318.719
>>> opt.lux()
5470.72

OPT3001 Object Attributes

The OPT3001 public Object Attributes can tell you the start time start_time of the HDC2080 object and used like this:

>>> opt.start_time
611145275

Checking OPT3001 Is Ready

The OPT3001 can be send a message to see if it's ready. Like a 'ping' in network terminanology. In other words it will return a 'True' response on the I2C bus if it's ready to recieve commands. To do this:

>>> opt.is_ready()
True

Errors From OPT3001

If the OPT3001 is not responding to messages, there is an electrical fault between the microcontroller and the tile sensor, or the firmware is not configured to use the I2C bus you will see an error generated on the repl like this:

>>> opt.is_ready()
The I2C bus is not responding to the I2C device address of: 64
Error value: [Errno 19] ENODEV
False
>>>
>>> opt.lu()
The I2C bus is not responding to the I2C device address of: 64
Error value: [Errno 19] ENODEV
0

Notice that the sensor object is still handling API calls. In this case the light sensor reading responds with '0'. This is not the actual lux or the lux value on the tile. It's a default software value that is returned by the OPT Sensor object.

PIR Sensor

The SR-501 PIR sensor documentation can be found here. The pin configuration is:

Pin Configuration

Pin Number Pin Name Description
1 Vcc Input voltage is +5V for typical applications. Can range from 4.5V- 12V
2 High/Low Ouput (Dout) Digital pulse high (3.3V) when triggered (motion detected) digital low(0V) when idle(no motion detected
3 Ground Connected to ground of circuit

PIR Image2

Repeatable (H) Mode

In Repeatable(H) mode the output pin Dout will go high (3.3V) when a person is detected within range and goes low after a particular time (time is set by “Off time control” potentiometer). In this mode the output pin will go high irrespective of whether the person is still present inside the range or has left the area. The sensitivity can be set using the “sensitivity control” potentiometer

Non Repeatable (L) Mode

In “I” mode the output pin Dout will go high (3.3V) when a person is detected within range and will stay high as long as he/she stays within the limit of the Sensors range. Once the person has left the area the pin will go low after the particular time which can be set using the potentiometer. The sensitivity can be set using the “sensitivity control” potentiometer

PIR Setup

The PIR sensor is defaulted to 'Repeatable' mode. Meaning it will go 'high' when it detects movement and keeps it high for a wait period. To setup the sensor we reduce the wait period to it's minimum amount - 4 seconds - by turning the time delay adjust pot to the minimum amount. This gives a good signal pulse to be captured by the PIR driver and processed.

Testing The Driver

The driver for the sensor is here. The sr_501_sensor.py file is really a wrapper over the micropython interrupt handlers. It allows you to create an object to manage your connection, get basic information from your PIR sensor and provide the object a callback function to be called when signals are detected from the PIR sensor.

Start PIR Sensor

A basic example with a sensor having pin 2 connected to X1 on the micropython board, pin 1 to VCC and pin 3 to ground (GND). You can easily create a PIR object and test with the following code:

/> rshell
/> repl
>>> import pyb
>>> import time
>>> import sr_501_sensor
>>> from sr_501_sensor import PIR
>>> p1 = PIR(pir_pin_id='X1')        # Creates a PIR object
>>> p1.start()                       # Starts the PIR sensor to detect objects.
(True, None)
>>> PIR callback called with line number:  0
*** Test callback function ***
    Line value is:    0 
    Program Time is:  611147966
PIR callback called with line number:  0

Getting Statistics

To get statistics from the PIR sensor you can call the methods pir_stats() and pir_total() like this:

>>> p1.pir_stats()
{'Last Event': 611150071, 'Trigger Events': 16, 'Start Time': 611145275}
>>>  
>>> p1.pir_total()
16
>>>

The pir_total method returns the total number of times the sensor has detected objects since the controller has been started.

The pir_stats method returns three things:

  1. the last time it detected an object,
  2. the start time of the PIR object i.e. since the object was instantiated; and
  3. how many times it has detected objects.

Detecting Current Activity

The PIR sensor has two methods to find out it's current state. There are two states to worry about here, the first tells you if the PIR sensor has been activated to detect objects and is called is_active.

The second method tells you if it is currently detecting something and is called is_currently_active. Things to note, is_currently_active is really useful as a debug tool. It allows you to find out if the pin is 'high' when issued. Examples of using the methods can be used like this:

>>> p1.is_active()
True
>>> 
>>> p1.is_currently_active()
0
>>> p1.is_currently_active()
1
>>>

PIR Object Attributes

The PIR public Object Attributes can tell you the start time start_time of the PIR object, and the current PIR pin pir_pin. Examples of using the methods can be used like this:

>>> p1.start_time
611145275
>>> p1.pir_pin
'X1'
>>>

Stopping the PIR

The PIR object can be stopped. In other words it will no longer report when objects are being detected via the interrupt handler using the stop() method. This can be run simple like:

>>> p1.stop()
(True, 'OK')
>>>

Microwave Radar Sensor

The RCWL-0516 Microwave Radar sensor documentation can be found here. There is also a GitHub repo with more information here. The sensor works using Doppler effect with an output frequency around 3GHz. Again for detailed information on the electrical workings of the sensor please refer to the link above written by Jdesbonnet.

The pin configuration is:

Pin Configuration

Pin Function
3V3 3.3V regulated output. Max 100mA (?)
GND Ground
OUT Digital pulse high (3.3V) when triggered (motion detected). 0V normally.
VIN 4 - 28V supply voltage
CDS LDR 10-20k RL, U_LDR > 0.7V = On

Here we use Pin 'GND', 'OUT' and 'VIN'. Where the ground (GND) is connected to the ground terminal of the micropython board, 'VIN' is connected to Pin 'VIN' (Pin 5 on WBUS-DIP68) and 'OUT' is configured to the Pin used in your code to detect movement.

RCWL-0516 board

Microwave Radar Sensor Setup

The Microwave Radar sensor is defaulted to detect and hold the 'OUT' Pin high for 4 seconds after detecting movement. Meaning it will go 'high' when it detects movement and keeps it high for this wait period.

Testing The Driver

The driver for the sensor is here. The rcwl_0516_sensor.py file is really a wrapper over the micropython interrupt handlers. It allows you to create an object to manage your connection, get basic information from your Microwave Radar sensor and provide the object a callback function to be called when signals are detected from the Microwave Radar sensor.

Start Microwave Radar Sensor

A basic example with a sensor having pin 3 connected to X1, pin 4 to VCC and pin 2 to ground (GND) on the Micropython Board. You can easily create a Microwave Radar sensor object and test with the following code:

/> rshell
/> repl
>>> import pyb
>>> import time
>>> import rcwl_0516_sensor
>>> from  rcwl_0516_sensor import MicrowaveRadar
>>> mr1 = MicrowaveRadar(mr_pin_id='X2')        # Creates a MicrowaveRadar object
>>> mr1.start()                                 # Starts the MicrowaveRadar sensor to detect objects.
(True, None)
>>> MicrowaveRadar callback called with line number:  1
*** Test callback function ***
    Line value is:    1 
    Program Time is:  611147966
MicrowaveRadar callback called with line number:  1

Getting Statistics

To get statistics from the MicrowaveRadar sensor you can call the methods mr_stats() and mr_total() like this:

>>> mr1.mr_stats()
{'Last Event': 611150071, 'Trigger Events': 16, 'Start Time': 611145275}
>>>  
>>> mr1.mr_total()
16
>>>

The mr_total method returns the total number of times the sensor has detected objects since the controller has been started.

The mr_stats method returns three things:

  1. the last time it detected an object,
  2. the start time of the MicrowaveRadar object i.e. since the object was instantiated; and
  3. how many times it has detected objects.

Detecting Current Activity

The MicrowaveRadar sensor has two methods to find out it's current state. There are two states to worry about here, the first tells you if the MicrowaveRadar sensor has been activated to detect objects and is called is_active.

The second method tells you if it is currently detecting something and is called is_currently_active. Things to note, is_currently_active is really useful as a debug tool. It allows you to find out if the pin is 'high' when issued. Examples of using the methods can be used like this:

>>> mr1.is_active()
True
>>> 
>>> mr1.is_currently_active()
0
>>> mr1.is_currently_active()
1
>>>

MicrowaveRadar Object Attributes

The MicrowaveRadar public Object Attributes can tell you the start time start_time of the MicrowaveRadar object, and the current MicrowaveRadar pin mr_pin. Examples of using the methods can be used like this:

>>> mr1.start_time
611145275
>>> mr1.mr_pin
'X2'
>>>

Stopping the MicrowaveRadar

The MicrowaveRadar object can be stopped. In other words it will no longer report when objects are being detected via the interrupt handler using the stop() method. This can be run simple like:

>>> mr1.stop()
(True, 'OK')
>>>

Finding Info

The MicrowaveRadar object has a name attribute which can be queried. It provides the description of the currently instantiated object and can be used like this:

>>> 
>>> mr1.name
'Microwave Radar Object for RCWL-0516 Sensor'
>>>

OLED Display

The OLED Display driver documentation can be found here. The OLED Display driver is a monochrome 128x64 Dot Matrix display. The version used in the lab is controlled over an I2C protocol Pin. Fortunately there is already a driver written for this display which is here. This driver file is copied locally to our project directory and used to control the display.

The pin configuration is:

Pin Configuration

Pin Number Pin Name Description
1 Ground Connected to ground of circuit
2 Vcc Vcc between 3.3V to 5V
3 SCL I2C Clock line
4 SDA I2C Data line

PIR Image2

The image above is slightly different to the lab version in that Ground (GND) and Power (Vcc) are reversed. To use the OLED display we connected Pins:

  • Pin 1 to GND (Pin 1 or 2 on the WBUS-DIP68)
  • Pin 2 to VIN (Pin 5 on WBUS-DIP68)
  • Pin 3 (SCL) to X9 (Pin 48 on WBUS-DIP68). You can see Pins used on the microcontroller for I2C here.
  • Pin 3 (SDC) to X10 (Pin 50 on WBUS-DIP68). You can see Pins used on the microcontroller for I2C here.

Possible Pin Configuration

The OLED Display uses the I2C bus on the microcontroller. To find out what possible Pin's can be used for the I2C bus you can check here. Possible Pin's are X9, X10 and Y9, Y10 for SCL (clock) and SDA (data) lines respectively. i.e. there are 2 I2C bus controllers that are exposed on the board. As mentioned above, this was tested using Pin X9 and X10.

Testing The Driver And OLED Display

The driver for the OLED is already written and part of the micropython github repo here. The driver is also copied locally onto our test-programs directory and our dirvers directory.

Setup Driver

To setup the driver to test, simple copy it to the microcontroller

/> rshell
/>  cp ssd1306.py /flash

Driver Description And Methods/Functions

The driver sub classes the frambuf class in micropython. It provides functions to:

  • initialize the display for a set size and width;
  • power off;
  • power on;
  • set contrast;
  • invert display;
  • show a set frame;
  • control as an I2C or SPI bus; and
  • write text to be displayed at a particular 'x' and 'y' position.

Lets look at trying a simple hello world to the screen.

Creating The SSD1306 Object

Assuming you have copied the file onto your flash drive on the microcontroller you first have to import the driver, then create the object using the correct screen size and I2C address to instantiate the object.

>>> import ssd1306
>>> from machine import Pin
>>> from machine import I2C
>>> from ssd1306 import SSD1306_I2C
>>> i2c = I2C(scl=Pin('X9'), sda=machine.Pin('X10'))       # 2) Create i2c object
>>> oled = SSD1306_I2C(128, 64, i2c, 0x3c)                 # 3) Create OLED object
>>> i2c.scan()                                             # 4) Check the device is on the bus
[60]
  1. We first import the classes Pin, I2C, and SSD1306_I2C. Note that we are using the I2C OLED, so we are using this class which sub classes SSD1306.
  2. We then create an i2c object which binds SCL to Pin X9, and SDA onto Pin X10. This attaches the protocol to the Pin's that we have physically attached the OLED to.
  3. We create our OLED Object and tell it the horizontal, vertical size, the i2c bus object, and the address the OLED has. In our case, the OLED has address 60 in decimal - hence 3C in hex.
  4. We can check that the OLED device is responding to that address by scanning the I2C bus. It responds as 60 which is correct

Printing To The OLED

To print to the OLED it's a 3 step process.

  1. Clear the screen buffer of any images and text
  2. Place your text onto the screen. At this point it will not show anything.
  3. Telling the screen to show the text. It's done this way due to the delay in sending the information to the screen over the bus. Better do this first for the screen to place into it's frame buffer. Then send the command to make that frame buffer active.
>>> oled.fill(0)                      # 1) clear the screen buffer
>>> oled.text("Hello World", 0, 0)    # 2) Place the text into the screen buffer at 'x' & 'y' co-ordinate 0
>>> oled.show()                       # 3) Tell the OLED to display this screen buffer

Printing Multiple Lines

To print multiple lines you need to position each line approx 10 pixels down from the previous. In this case the top of the screen is '0' and as you move down 'y' increases in size. Hence printing 3 lines to the screen looks like this:

>>> oled.fill(0)
>>> oled.text("Hello World", 0, 0)
>>> oled.text("Hello World 2", 0, 10)
>>> oled.text("Hello World 3", 0, 20)
>>> oled.show()

Inverting The Display

To invert the display simply pass 'True' to the invert function. Or 'False' if it's already inverted.

>>> oled.invert(True)

Running Test Script

There is a test script which will print text to the screen then delete and show through various positions. To run the script first copy to the microcontroller and run.

/> rshell
/> cp test_oled.py /flash
/> repl
>>>> import test_oled
*** Starting test to OLED display ****
Printing: "Hello World"
Printing: "Hello World" on 2nd Line
Printing: "Hello World" on 3nd Line
Printing: "Hello World" on 4th Line
Printing: "Hello World" on 5th Line
Printing: "Hello World" on 6th Line
Printing: "Hello World" on 7th Line
Printing: "Hello World" moving right
Printing: "Hello World" moving right
Printing: "Hello World" moving right
Printing: "Hello World" moving right
Printing: "Hello World" moving right
Printing: "Hello World" moving right
Printing: "Hello World" moving right
Printing: "Hello World" moving right
Printing: "Hello World" moving right
Printing: "Hello World" moving right
Printing: "Hello World" moving right
Printing: "Hello World" moving right
Printing: "Hello World" moving right
Printing: "Hello World" moving right
Printing: "Hello World" moving right
Now inverting Display