This shows you the differences between two versions of the page.
| Next revision | Previous revision | ||
| en:iot-open:remotelab:ume:arancino [2019/09/27 08:12] – created salvatdi | en:iot-open:remotelab:ume:arancino [2020/07/20 09:00] (current) – external edit 127.0.0.1 | ||
|---|---|---|---|
| Line 1: | Line 1: | ||
| - | ===== SmartMe Network Laboratory - Arancino ===== | ||
| - | /* //Give an information, | ||
| + | ===== SmartMe Network Laboratory - Arancino ===== | ||
| The SmartMe lab is located at the Engineering building of the University of Messina, in Messina, Italy. | The SmartMe lab is located at the Engineering building of the University of Messina, in Messina, Italy. | ||
| + | |||
| + | ==== Introduction ==== | ||
| + | |||
| + | Its main goal is to provide a single-node testbed consisting of a next-generation “combo” board, a.k.a. Single-Board Computer (SBC) mainly focusing on smart environment monitoring scenarios. To this purpose, 1 node has been equipped and made available to students for practicing in these contexts. This node is a combo SBC which combines onto the same node a so-called “carrier board”, in this case, an Arancino(TM) by smartme.IO, with an Arduino-like MCU (based on an ARM Cortex M0+ @48MHz) built-in, hosting a Raspberry Pi 3 Compute Module (CM3). In this section, we will focus on this Arancino node and its sensors/ | ||
| + | |||
| + | ==== Prerequisites ==== | ||
| + | |||
| + | To approach this laboratory, the student should grasp: | ||
| + | * basic Node-RED concepts like nodes, flows, deploy and dashboard; | ||
| + | * quantities and metrics related to the physical quantities that can be detected using BME-class sensors: temperature (°C and F), relative humidity (%), pressure (hPa). | ||
| + | |||
| + | ==== Technical details ==== | ||
| + | |||
| + | The Arancino node is Internet-connected and reachable over its (hosted) IoT gateway (the CM3). The Arancino board is depicted in the following photo: | ||
| + | |||
| + | FIGURE arancino | ||
| + | |||
| + | The Lab configuration is shown in the figure below: | ||
| + | |||
| + | FIGURE internet-router-arancino-cam | ||
| + | |||
| + | ==== Node schematic ==== | ||
| + | |||
| + | The Arancino is interconnected/ | ||
| + | |||
| + | FIGURE riquadro sx in basso (+sensore) | ||
| + | |||
| + | ==== Sensors ==== | ||
| + | |||
| + | The node is equipped with the MIKROE-2467 “Environment click” [1] sensor shield, a mikroBUS™-socket compatible module, which hosts the BME680 environmental sensor from Bosch (datasheet available online [2]). This click module is designed to run on a 3.3V power supply. | ||
| + | The BME680 is a (combined) digital gas, humidity, pressure, and temperature sensor based on proven sensing principles. | ||
| + | The humidity sensor provides an extremely fast response time for fast context awareness applications and high overall accuracy over a wide temperature range. The pressure sensor is an absolute barometric pressure sensor with extremely high accuracy and resolution. | ||
| + | The integrated temperature sensor has been optimized for the lowest noise and highest resolution. Its output is used for temperature compensation of the pressure and humidity sensors and can also be used for estimation of the ambient temperature. | ||
| + | The gas sensor within the BME680 can detect a broad range of gases to measure indoor air quality for personal well being. Gases that can be detected by the BME680 include Volatile Organic Compounds (VOC) from paints (such as formaldehyde), | ||
| + | |||
| + | ^ Parameter ^ BME680 | ||
| + | |Operating Supply Voltage |1.71V to 3.6V | | ||
| + | |Current Consumption | 2.1μA @1Hz (humidity + temperature) | | ||
| + | | " | ||
| + | | " | ||
| + | | " | ||
| + | | Humidity Range |0‒100% r.H. | | ||
| + | |Temperature Range| -40‒+85°C | | ||
| + | | Pressure Range |300‒1100 hPa | | ||
| + | | Package | 3.0mm x 3.0mm x 0.93mm (metal lid LGA) | | ||
| + | | Resolution |20-bit (IIR)| | ||
| + | |||
| + | It can be used to test indoor air quality, to control HVAC (heating, ventilation, | ||
| + | As shown in the previous figure, the 1Wire mode was chosen while the operating voltage is 5V. The sensor is connected to pin 8 of Arduino Uno. | ||
| + | |||
| + | [1] https:// | ||
| + | |||
| + | [2] https:// | ||
| + | |||
| + | ==== Actuators ==== | ||
| + | |||
| + | There are no mechanical actuators or displays in this laboratory. The node is nevertheless equipped with three LEDs, including an MCU-controlled one. By default, i.e., after MCU reset (which may be triggered by quick double-click on the corresponding button) the aforementioned LED starts “breathing”, | ||
| + | |||
| + | ==== Power supply ==== | ||
| + | The node is powered by an external DC (5V) power supply over USB. | ||
| + | Software, libraries, and externals | ||
| + | The following libraries are required to run the example proposed below for the hands-on labs: | ||
| + | * SPI | ||
| + | * Adafruit Sensor | ||
| + | * Adafruit BME680 | ||
| + | * Arancino | ||
| + | * BME680 sensor library by Adafruit depends on the “Adafruit Unified Sensor”, so it is mandatory to include this library. | ||
| + | The BME680 sensor library can be imported (including required deps) to the source code via: | ||
| + | |||
| + | <code c> | ||
| + | #include < | ||
| + | #include < | ||
| + | #include < | ||
| + | </ | ||
| + | |||
| + | Then configure your BME680 sensor: | ||
| + | <code c> | ||
| + | #define BME_SCK 13 | ||
| + | #define BME_MISO 12 | ||
| + | #define BME_MOSI 11 | ||
| + | #define BME_CS 10 | ||
| + | #define SEALEVELPRESSURE_HPA (1013.25) | ||
| + | Adafruit_BME680 bme680_sensor; | ||
| + | // Set up oversampling and filter initialization | ||
| + | bme680_sensor.setTemperatureOversampling(BME680_OS_8X); | ||
| + | bme680_sensor.setHumidityOversampling(BME680_OS_2X); | ||
| + | bme680_sensor.setPressureOversampling(BME680_OS_4X); | ||
| + | bme680_sensor.setIIRFilterSize(BME680_FILTER_SIZE_3); | ||
| + | bme680_sensor.setGasHeater(320, | ||
| + | </ | ||
| + | |||
| + | MQTT connectivity protocol requires a dedicated library. The “MQTT” library uses the Arduino Ethernet Client API for interacting with the underlying network hardware. This library provides a client for doing simple publish/ | ||
| + | |||
| + | <code c> | ||
| + | #include < | ||
| + | </ | ||
| + | |||
| + | ==== “platformio.ini” (Project Configuration File) ==== | ||
| + | |||
| + | The Project configuration file is named platformio.ini. | ||
| + | < | ||
| + | [env:uno] | ||
| + | platform = atmelsam | ||
| + | board = arancino | ||
| + | framework = arduino | ||
| + | |||
| + | lib_ldf_mode=deep+ | ||
| + | lib_compat_mode=strict | ||
| + | |||
| + | lib_deps = | ||
| + | | ||
| + | | ||
| + | | ||
| + | |||
| + | build_flags = | ||
| + | | ||
| + | | ||
| + | </ | ||
| + | |||
| + | ==== Communication ==== | ||
| + | |||
| + | The user can connect and program the node (micro)controller by using the Distancelab environment by booking it for the time he needs. The user can use the Redis protocol. Redis stands for ... | ||
| + | Redis is a machine-to-machine (M2M) connectivity protocol usable for “Internet of Things” solutions. MQTT is a simple messaging protocol, designed for constrained devices with low-bandwidth. So, it’s the perfect solution for Internet of Things applications. | ||
| + | This publish/ | ||
| + | publish messages specifying a topic so that other clients that have subscribed to that topic will be able to receive those messages; | ||
| + | receive messages subscribing to a specific topic. | ||
| + | |||
| + | FIGURE | ||
| + | |||
| + | ==== Limits ==== | ||
| + | |||
| + | A single user only can program the (micro)controller at any time. But each user, connected to the Distancelab (board)-hosted Node-RED instance, can concurrently read/ | ||
| + | |||
| + | M1: Redis-based MCU/MPU comm, including MPU-side NodeRED-based viz | ||
| + | |||
| + | ==== Target group ==== | ||
| + | |||
| + | This hands-on lab guide is intended for master students. Other target groups may benefit from it only if they follow it after having dealt with all the exercises proposed which belong to lower levels of difficulty. | ||
| + | |||
| + | ==== Prerequisites ==== | ||
| + | |||
| + | Liquid Crystal library, you may refer to the B1 exercise. | ||
| + | RGB LED. All the nodes of SmartME Network Laboratory are equipped with an RGB LED of which, however, at the moment it is only possible to use the green light component. This single colour component can be considered and effectively managed as a separate LED. | ||
| + | To turn on the green LED, you have to follow three steps: | ||
| + | first, you have to define a variable int that will hold the number of the pin that the LED is connected to (int greenPin = 3;); | ||
| + | second, you need to configure this variable in output mode (OUTPUT). You do this with a call to the pinMode(pin, | ||
| + | finally, you need to send to this variable a HIGH signal by using the digitalWrite(pin, | ||
| + | The digital pins either give you 5V (when turned HIGH) or 0V (when turned LOW) and the output is a square wave signal. | ||
| + | PWM stands for Pulse Width Modulation and it is a technique used in controlling the brightness of the LED. The PWM pins are labelled with ~ sign. | ||
| + | The function analogWrite() can be used to generate a PWM signal in those digital pins that are labelled with ~ sign. | ||
| + | The frequency of this generated signal for most pins will be about 490Hz and you can give the value from 0-255 using this function. | ||
| + | * analogWrite(0) means a signal of 0% duty cycle. | ||
| + | * analogWrite(127) means a signal of 50% duty cycle. | ||
| + | * analogWrite(255) means a signal of 100% duty cycle. | ||
| + | The function random() generates pseudo-random numbers. The syntax is random(max) or random(min, max), where min represents the lower bound of the random value, inclusive (optional); and max represents the upper bound of the random value, exclusive. The function returns a long random number between min and max-1. | ||
| + | |||
| + | The circuit: | ||
| + | |||
| + | RGB GREEN pin = Arduino pin 3 (~) | ||
| + | |||
| + | ==== Scenario ==== | ||
| + | |||
| + | Initialize the LCD screen with the label “rand value”, then calculates a random value. If randomValue is lower than lowThreshold, | ||
| + | |||
| + | ==== Result ==== | ||
| + | |||
| + | You should see the LED on or off for 1 second, a second if the value is greater or less than the predefined threshold values. Next, you should see the randomly calculated value between 0 and 255 on the LCD, at that point, the LED should assign a brightness associated with that value, and keep it for 3 seconds. | ||
| + | |||
| + | ==== Start ==== | ||
| + | |||
| + | There are no special steps to be performed. | ||
| + | |||
| + | ==== Steps ==== | ||
| + | |||
| + | === Step 1 === | ||
| + | |||
| + | Include required libraries: | ||
| + | <code c> | ||
| + | #include < | ||
| + | #include < | ||
| + | #include < | ||
| + | #include < | ||
| + | #include < | ||
| + | </ | ||
| + | |||
| + | and define a number of directives: | ||
| + | |||
| + | <code c> | ||
| + | #define DEBUG true // enable debug | ||
| + | #define BME_SCK 13 | ||
| + | #define BME_MISO 12 | ||
| + | #define BME_MOSI 11 | ||
| + | #define BME_CS 10 | ||
| + | #define SEALEVELPRESSURE_HPA (1013.25) | ||
| + | </ | ||
| + | |||
| + | Declare the sensor(s) object, a number of useful vars and constants, and assign them (e.g., initial) values when required: | ||
| + | |||
| + | <code c> | ||
| + | Adafruit_BME680 bme680_sensor; | ||
| + | // Used here to set a pin number: | ||
| + | const int ledPin = LED_BUILTIN; | ||
| + | int ledState = LOW; // ledState used to set the LED | ||
| + | unsigned long previousMillis = 0; // will store last time LED was updated | ||
| + | unsigned long currentMill=0; | ||
| + | const long interval = 150; // interval at which to blink (milliseconds) | ||
| + | float humidity_read; | ||
| + | float temperature_read; | ||
| + | float pressure_read; | ||
| + | unsigned long previousMillisTemp = 0; // environment reading interval | ||
| + | const long intervalTemp = 400; // interval at which to blink(milliseconds) | ||
| + | </ | ||
| + | |||
| + | Functions declarations cannot be omitted (when using .cpp extension instead of .ino one): | ||
| + | |||
| + | <code c> | ||
| + | void bme680_begin(); | ||
| + | void bme680_read(); | ||
| + | void blink_status(); | ||
| + | </ | ||
| + | |||
| + | === Step 2 === | ||
| + | |||
| + | Functions definitions for: BME680 sensor initialization and settings configuration ('' | ||
| + | |||
| + | <code c> | ||
| + | void bme680_begin(){ | ||
| + | if(!bme680_sensor.begin()) { | ||
| + | Arancino.println(" | ||
| + | while (1); | ||
| + | } | ||
| + | // Set up oversampling and filter initialization | ||
| + | bme680_sensor.setTemperatureOversampling(BME680_OS_8X); | ||
| + | bme680_sensor.setHumidityOversampling(BME680_OS_2X); | ||
| + | bme680_sensor.setPressureOversampling(BME680_OS_4X); | ||
| + | bme680_sensor.setIIRFilterSize(BME680_FILTER_SIZE_3); | ||
| + | bme680_sensor.setGasHeater(320, | ||
| + | } | ||
| + | |||
| + | void bme680_read(){ | ||
| + | unsigned long currentMillis = millis(); | ||
| + | if(currentMillis - previousMillisTemp >= intervalTemp) { | ||
| + | previousMillisTemp = currentMillis; | ||
| + | if(!bme680_sensor.performReading()) { | ||
| + | Arancino.println(" | ||
| + | return; | ||
| + | } | ||
| + | temperature_read = bme680_sensor.temperature; | ||
| + | humidity_read = bme680_sensor.humidity; | ||
| + | pressure_read = bme680_sensor.pressure / 100.0; | ||
| + | Arancino.set(" | ||
| + | Arancino.set(" | ||
| + | Arancino.set(" | ||
| + | } | ||
| + | } | ||
| + | |||
| + | void blink_status(){ | ||
| + | | ||
| + | if(currentMill - previousMillis >= interval) { | ||
| + | previousMillis = currentMill; | ||
| + | if(ledState == LOW) { | ||
| + | ledState = HIGH; | ||
| + | } else { | ||
| + | ledState = LOW; | ||
| + | } | ||
| + | digitalWrite(ledPin, | ||
| + | } | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | === Step 3 === | ||
| + | |||
| + | Initialize the Redis structures (Arancino.begin()), | ||
| + | |||
| + | <code c> | ||
| + | void setup(void) | ||
| + | { | ||
| + | Arancino.begin(); | ||
| + | Arancino.publish(0," | ||
| + | // redis-side | ||
| + | Wire.begin(); | ||
| + | bme680_begin(); | ||
| + | pinMode(ledPin, | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | === Step 4 === | ||
| + | |||
| + | Implement '' | ||
| + | - perform the readings (see Step 2 for more details); | ||
| + | - blink the led (see Step 2 for more details). | ||
| + | |||
| + | |||
| + | <code c> | ||
| + | void loop() | ||
| + | { | ||
| + | bme680_read(); | ||
| + | blink_status(); | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | ==== Result validation ==== | ||
| + | |||
| + | Observe the state of the LED for 1 second, this status will depend on the random number calculated and the threshold values that have been set. Observe the random value calculated on the display monitor. Observe how the random value affects the LED brightness for 3 seconds. | ||
| + | |||
| + | ==== Platformio.ini ==== | ||
| + | |||
| + | <code c> | ||
| + | [env:uno] | ||
| + | platform = atmelsam | ||
| + | board = arancino | ||
| + | framework = arduino | ||
| + | |||
| + | lib_ldf_mode=deep+ | ||
| + | lib_compat_mode=strict | ||
| + | |||
| + | lib_deps = | ||
| + | Arancino | ||
| + | Adafruit Unified Sensor | ||
| + | Adafruit BME680 Library | ||
| + | |||
| + | build_flags = | ||
| + | -Wno-reorder | ||
| + | -Wno-return-type | ||
| + | </ | ||
| + | |||
| + | ==== aran.cpp ==== | ||
| + | |||
| + | <code c> | ||
| + | #include < | ||
| + | #include < | ||
| + | #include < | ||
| + | #include < | ||
| + | #include < | ||
| + | |||
| + | #define DEBUG true // enable debug | ||
| + | #define BME_SCK 13 | ||
| + | #define BME_MISO 12 | ||
| + | #define BME_MOSI 11 | ||
| + | #define BME_CS 10 | ||
| + | |||
| + | #define SEALEVELPRESSURE_HPA (1013.25) | ||
| + | |||
| + | Adafruit_BME680 bme680_sensor; | ||
| + | |||
| + | // Used here to set a pin number: | ||
| + | const int ledPin = LED_BUILTIN; | ||
| + | |||
| + | int ledState = LOW; // ledState used to set the LED | ||
| + | |||
| + | unsigned long previousMillis = 0; // will store last time LED was | ||
| + | //updated | ||
| + | unsigned long currentMill=0; | ||
| + | |||
| + | const long interval = 150; // interval at which to blink | ||
| + | // (milliseconds) | ||
| + | |||
| + | float humidity_read; | ||
| + | float temperature_read; | ||
| + | float pressure_read; | ||
| + | |||
| + | unsigned long previousMillisTemp = 0; // environment reading | ||
| + | // interval | ||
| + | const long intervalTemp = 400; // interval at which to blink | ||
| + | // (milliseconds) | ||
| + | |||
| + | void bme680_begin(); | ||
| + | void bme680_read(); | ||
| + | void blink_status(); | ||
| + | |||
| + | void bme680_begin(){ | ||
| + | if(!bme680_sensor.begin()) { | ||
| + | Arancino.println(" | ||
| + | while (1); | ||
| + | } | ||
| + | |||
| + | // Set up oversampling and filter initialization | ||
| + | bme680_sensor.setTemperatureOversampling(BME680_OS_8X); | ||
| + | bme680_sensor.setHumidityOversampling(BME680_OS_2X); | ||
| + | bme680_sensor.setPressureOversampling(BME680_OS_4X); | ||
| + | bme680_sensor.setIIRFilterSize(BME680_FILTER_SIZE_3); | ||
| + | bme680_sensor.setGasHeater(320, | ||
| + | } | ||
| + | |||
| + | void bme680_read(){ | ||
| + | unsigned long currentMillis = millis(); | ||
| + | if(currentMillis - previousMillisTemp >= intervalTemp) { | ||
| + | previousMillisTemp = currentMillis; | ||
| + | if(!bme680_sensor.performReading()) { | ||
| + | Arancino.println(" | ||
| + | return; | ||
| + | } | ||
| + | temperature_read = bme680_sensor.temperature; | ||
| + | humidity_read = bme680_sensor.humidity; | ||
| + | pressure_read = bme680_sensor.pressure / 100.0; | ||
| + | Arancino.set(" | ||
| + | Arancino.set(" | ||
| + | Arancino.set(" | ||
| + | } | ||
| + | } | ||
| + | |||
| + | void blink_status(){ | ||
| + | | ||
| + | if(currentMill - previousMillis >= interval) { | ||
| + | previousMillis = currentMill; | ||
| + | if(ledState == LOW) { | ||
| + | ledState = HIGH; | ||
| + | } else { | ||
| + | ledState = LOW; | ||
| + | } | ||
| + | digitalWrite(ledPin, | ||
| + | } | ||
| + | } | ||
| + | |||
| + | void setup(void) | ||
| + | { | ||
| + | Arancino.begin(); | ||
| + | Arancino.publish(0," | ||
| + | // redis-side | ||
| + | Wire.begin(); | ||
| + | bme680_begin(); | ||
| + | pinMode(ledPin, | ||
| + | } | ||
| + | |||
| + | void loop() | ||
| + | { | ||
| + | bme680_read(); | ||
| + | blink_status(); | ||
| + | } | ||
| + | </ | ||