Introduction: For Newbies at Arduino Programming: Telling the Direction of Fire in 3 Seconds WITH PIXEL LIGHTS!

During my high-school sophomore year, the 3rd floor of our house lighted on fire due to a short circuit. Fortunately, my family was away on vacation for Christmas. But if we were home, wouldn't it be crucial to tell the direction of fire quickly so that we know the direction to evacuate?

Consider another situation. You really hope to learn Arduino programming, which enables you to build both functional and decorative things. First, you need to get past the basics of the wiring and the programming language. But after you get past this hurdle, whenever you hope to create with some complexity, tutorials online often consist of "replicate this wiring over here; then copy and paste the code into Arduino". Do you hope to learn the "why" under each part of a tutorial? Do you hope to be able to alter parts of a tutorial to fit with your own needs?

If you have answered "yes" to any of the three questions above, then you are at the right place. In this tutorial, we will be going step-by-step from 0 to 100%. By the end of this tutorial, you will understand the underlying functions and challenges. You will know the different skills, such as integrating sensors, programming RGB colors, and using arrays, that can be used elsewhere. I gradually learned those skills as a newbie myself, so I understand your potential challenges and I fully trust that you can do this! Have fun building!

Step 1: Potential Challenges and Safety Hazards

This tutorial does not require complex skills of Arduino programming, as small steps will be explained to lead you up to the final product. However, there is a tiny bit of soldering involved with this neopixel ring here so please be careful when you are on this step! It is not complex though: drop the solder and attach the wire.

Step 2: Let's Go Over Our Materials First!

Required materials are the materials necessary to complete the final product.

Optional materials are the materials only necessary to complete mini-activities.

Required materials:

-1 Arduino board (preferably Arduino Uno, to store your program)

-1 Base Shield V2 (this project requires a bunch of sensors, and this base shield attached to your Arduino keeps it tidy!)

-7 MLX90615 infrared temperature sensors (infrared temperature sensors are capable at telling differences in temperature even when they are not spaced far apart; if you are using smoke sensors to detect fire, you would need to place them 15m apart!)

-1 neopixel ring

-Arduino software on computer (this can be downloaded for free on https://www.arduino.cc/en/main/software)

-1 5V resistor (which will be attached to the neopixel ring)

-7 Grove 4 pin connector cables

-Arduino Breadboard

-Soldering tools (to solder wires onto the neopixel ring)

Optional materials:

-3 RGB led lights

-3 Arduino digital capacitive touch sensors

-1 Arduino breadboard

-20+ M-M wires (M means male; wires with pins pointing out on both sides)

Step 3: Obtaining Temperature With the Infrared Temperature Sensors

Before we tangle ourselves with using lights, we will first be learning how to obtain temperature from an infrared temperature sensor. This part of the tutorial is adapted from the webpage (http://wiki.seeedstudio.com/Grove-Digital_Infrared_Temperature_Sensor/) On this site, you will be able to download the demo code and incorporate it into your Arduino library. This is necessary because the demo code contains a set of codes that should be included to make the sensors function properly. The code for this inclusion is

#include "MLX90615.h"

SoftI2cMaster i2c_1(sda_1, scl_1);
MLX90615 mlx90615_1(DEVICE_ADDR, &i2c_1);

If you are doing multiple devices (as we are going to later on), you paste the last two lines of code again and change the number to 2 or whatever the number the sensor is given.

Then, the SDA and SCL ports need to be defined. SCL is the clock line, which is used to synchronize all data transfers. SDA is the data line. On the backside of the temperature sensor, you can see SDA and SCL. When you attach the SDA and SCL cords, they correspond directly to the Dx on the base shield. In this diagram, SCL is connected to D6 and SDA is connected to D7, so on code it is:

byte sda_1 = 7;
byte scl_1 = 6;

Note: It is totally okay if you later write byte sda_2 = 6 because SDA & SCL are separately defined!

Then we will be coding for void set up and void loop in the software. The void set up only runs once at the start of the program (because it is a "set up"!) while the loop will be run again and again.

void setup()
{Serial.begin(9600);

Serial.println("Setup...");}

The first line means to open the serial port and set data rate to 9600 bytes per second (bps).

The second line means to print and show your obtained data on the serial monitor.

There are a few rules that you should be aware of here:

At the end of a line you must use a semicolon, or there will be a compiler error.

Curly braces are used for telling the beginning and end of a statement, and an opening brace must be followed by a closing brace.

For the loop of getting the temperature, the code is:

void loop ()

{Serial.print("Object temperature: "); Serial.println(mlx90615_1.getTemperature(MLX90615_OBJECT_TEMPERATURE));

Serial.print("Ambient temperature: "); Serial.println(mlx90615_1.getTemperature(MLX90615_AMBIENT_TEMPERATURE));

delay(1000);}

This function allows you to print two things "Object temperature" and "Ambient temperature" with the mlx90615_1 sensor defined previously. By changing the delay time (currently 1 second or 1000 microseconds) you can play with the time intervals you want your sensors to wait before obtaining new temperature data.

This is the end of this set of code, and you can upload through pressing the green arrow (called "Upload) in the Arduino software. If the code does not upload properly, go to Tools - Port and check if you are connected to the right port. (If you are connected by USB, you would see a separate usb port than the normal bluetooth port) If you don't see the usb port try reattaching the usb cord or restarting your computer.

Once you wire up the sensor to D6 & D7 (on the big D6 port) and upload the code above, you will be able to see temperature data in the Arduino software through Tools -> Serial Monitor.

Step 4: Output? Input?

We want to make temperature change the color of a light. Therefore, the temperature is the input and the light's color is the output. On step 3 we went over how to obtain the input, so how do you use that information to affect the output?

In addition to our previous code, we can write up a command to turn pin 13 ON when a certain condition is reached. In the setup, you set 13 as output through pinMode (13, OUTPUT).

Then, in the loop section, you use the float function, which obtains data that is in decimal point format and is constantly changing. In this example, we name the object temperature as "tture" and add it to the previous code.

float tture = mlx90615.getTemperature(MLX90615_OBJECT_TEMPERATURE);

Then, after the same codes previously for obtaining temperature from the sensors, we command the pin 13 to act according to the data given. This time let's try a simple one: pin 13 turns on when temperature of the sensor exceeds 27, and turns off when the temperature is below 27. We use digital write to control the pin's behavior.

if (true > 27){

digitalWrite(13,HIGH);

}

else{

digitalWrite(13,LOW);

}

You can check this through putting your hand over the sensor. If pin 13 turns on, you would be able to see a small yellow light emerging.

Step 5: Programming RGB

You may be wondering, how could we create a range of colors with arduino? This can be achieved through programming a RGB light, which mixes red, green and blue values in different degrees to form various colors. RGB codes are given in the form (red value, green value, blue value). The maximum value given is 255. (255, 0,0) is red, (0,255,0) is green and (0,0,255). You can visit this link for a thorough color chart to create whichever colors you want: http://www.tayloredmktg.com/rgb/

On a standard Arduino RGB light, you can see how there are four cords, red, blue, green and ground. Similarly to the previous drill, you can define 9 as output red, 11 as output green and 12 as output blue. Then in the loop, instead of using digitalWrite you use analogWrite, in the format:

analogWrite (9, 200);

analogWrite (11, 100);

analogWrite (12, 100);

Step 6: How to Use a Range of Values: Changing One RGB Light With One Sensor

Let's do a mini-activity with the breadboard and the RGB light! The final product of this mini-activity would be a RGB light that changes from purple to red depending on the temperature around the sensor.

The wiring would consist of using the breadboard. You can see that on the left, there are two columns: negative and positive (indicated by the sign). On your Arduino you can see GND (ground) and 5V (power source). Plug one wire between a GND port and the end of the negative column. Plug one wire between a 5V port and the end of the positive column. Then, connect one wire between the negative and a row where the ground of the RGB light is in (on the two sides the columns are electrically connected, in the middle the rows are electrically connected, see the purple lines on picture 5). Then, the columns where the Red, Green and Blue pins are in are connected with pins on the Arduino via wires. In the following code, pin 10 on Arduino is connected with red, 11 with green and 12 with blue.

After we are done with the wiring, let's get to the coding.

#include "MLX90615.h"

byte scl_1 = 2;

byte sda_1 = 3;

int ledPin1 = 10; // red

int ledPin2 = 11; // green

int ledPin3 = 12; //blue

We define the 3 pins as 11, 12 and 13.

SoftI2cMaster i2c_1(sda_1, scl_1); MLX90615 mlx90615_1(DEVICE_ADDR, &i2c_1);

void setup() {

Serial.begin(9600);

Serial.println("Setup...");

pinMode(ledPin1, OUTPUT);

pinMode(ledPin2, OUTPUT);

pinMode(ledPin3, OUTPUT);

We set the three pins as output; other parts are explained previously.

void loop() {

float temperatureObj1 = mlx90615_1.getTemperature(MLX90615_OBJECT_TEMPERATURE);

float temperatureAmb1 = mlx90615_1.getTemperature(MLX90615_AMBIENT_TEMPERATURE);

Serial.print("Temp_1: ");

Serial.print(temperatureObj1);

Serial.print("`C ");

Serial.print(temperatureAmb1);

Serial.println("`C ");

Serial.println("\n=======================================\n\r");

delay (100);

This is the code for obtaining the temperature. Explanation can be found in previous steps.

if (temperatureObj1 > 23 && temperatureObj1 < 27) {

analogWrite (10, 148);

analogWrite (11, 0);

analogWrite (12, 220);

delay (100); }

if (temperatureObj1 > 27 && temperatureObj1 < 31) {

analogWrite (10, 0);

analogWrite (11, 0);

analogWrite (12, 205);

delay (100); }

if (temperatureObj1 > 31 && temperatureObj1 < 35) {

analogWrite (10, 0);

analogWrite (11, 205);

analogWrite (12, 0);

delay (100); }

if (temperatureObj1 > 35 && temperatureObj1 < 38) {

analogWrite (10, 255);

analogWrite (11, 255);

analogWrite (12, 0);

delay (100); }

if (temperatureObj1 > 38 && temperatureObj1 < 42) {

analogWrite (10, 255);

analogWrite (11, 0);

analogWrite (12, 0);

delay (100); }

else {

analogWrite (10,0);

analogWrite (11,0);

analogWrite (12,0);

delay(100);

}}

Similar to the use of conditions before, you can analogWrite conditions for each of the three colors. There is a 0.1 millisecond delay between the color changes corresponding to a temperature change. You can change the colors through obtaining RGB values on http://www.tayloredmktg.com/rgb/.

Step 7: Potential Challenges

There are a few potential challenges so far.

First: you need to make sure that the SCL and SDA ports on your program are correctly corresponding to your wiring. On the V2 base-shield, you can see the numbers like D2, D3, etc. so you know if your wiring is correct. One tip is that SDA is always 1 value higher than SCL! (e.g. sda = 3 scl = 2; sda= 4 scl = 3)

Secondly: sometimes a new sensor may just not work. Here are a few tips:

1. Make sure that the sensor cords are pulled separate.

2. Make sure that the cords are fully plugged in.

3. Retry plugging in the sensor.

Lastly, a common mistake is to type (temperatureObj1 > 23 && temperatureObj1 < 27) as if (temperatureObj1 > 23 & temperatureObj1 < 27), which will result in an uploading error. Remember to type && instead of &!

Step 8: Arrays

The function array is a collection of variables that are accessed with an index number. In this tutorial, it will be used to program the neopixel ring.

An array is difficult to conceptualize at first, but try imagining that there is a box that contains 5 cards. You pull out a card randomly and it gives you a value. Now imagine pulling out 3 cards from 3 boxes simultaneously, and their values form a RGB color.

Here is a simple code for showing 125 random colors:

int red[]={0,5,25,100,255};

int green[]={0,5,25,100,255};

int blue[]={0,5,25,100,255};

This is like putting cards in the red, green and blue boxes: you are putting in the collection of values.

void setup() {

pinMode(9,OUTPUT);//pin 9 for blue p

inMode(11,OUTPUT);//pin 10 for green

pinMode(12,OUTPUT);//pin 11 for red

pinMode(8,OUTPUT);

digitalWrite(8,LOW);//uses pin 8 as ground

This is simply defining 9, 11, and 12 as output and 8 as ground. If you have any confusions, refer to the previous steps.

void loop() {

for(int i=0; i<5; i++){

analogWrite(12,red[i]); }

for(int i=0; i<5; i++){

analogWrite(11,green[i]);

}

for(int i=0; i<5; i++){

analogWrite(9,blue[i]);

delay(500); }

}//end of void loop

Through the for(int i=0; i<5; i++) you choose an integer from 0 to 4. 0 corresponds to a value of 0, 1 to 5, 2 to 25, 3 to 100 and 4 to 255. And in the analogWrite function 12 is no longer matched with a value, instead it is matched with [i], the value on the card you randomly pulls. This is repeated fro green and blue, ending with a delay of 0.5 milliseconds.

Step 9: Introduction to the Neopixel Ring

The neopixel ring is like a string of RGB lights that is controlled by only three wires: ground, 5V, and signaling wire. Array is used in this case to control each individual light on the neopixel ring; for example, the first light would be called [0], the second light would be called [1], etc. The final product would include each infrared temperature sensor corresponding to a bright pixel light. In this context, there will not be a random card pulled, but instead you can control the lights on a neopixel ring separately through typing values onto cards that each control one light.

Sometimes you would need to solder the neopixel ring with wires. Moreover, between the neopixel ring and the signaling wire (on D1), you would need to attach a 5V resistor or the system would overheat. Here are a few tips with the soldering:

1. Test your soldering's tool's temperature; an ideal condition is when the solder melts in about half a second after contact

2. "Drop" a tiny ball of solder and make it solidify on the neopixel ring and the end of a wire. Then when you pull up the wire towards the ring, you can remelt the balls on both sides and connect the two ends easily.

3. DO NOT touch your soldering tool when you are not sure about if it is heating up or not! Instead, wipe it on a wet sponge and observe if it makes any sounds (a sound indicates that it is heating up). Tie up your hair and make sure that you have nothing hanging off your body (a necklace, for example). Be aware of the safety hazards :)

Step 10: 1 Neopixel Light With 1 Sensor

Now that we know about obtaining temperature, RGB and arrays, we can move on to our final step: connecting the sensors with the neopixel ring. As a start, we will be connecting just 1 light with 1 sensor. The wire connecting GND on the neopixel ring will be plugged into GND on the V2 Base Shield. The 5V wire will be plugged into 5V on the V2 Base Shield. The D1 (or the signal wire) can be plugged into D2 - D13 on the right of the Base Shield depending on your code. In this example we will be plugging it into D7. The wiring for the sensor is the same: pugged into D2.

Let me explain the code for doing this:

#include "MLX90615.h"

byte sda_1 = 3;

byte scl_1 = 2;

#define PIN 7

#define NUMPIXELS 6

Adafruit_NeoPixel strip = Adafruit_NeoPixel (7, PIN, NEO_GRB + NEO_KHZ800);

int sine[] = {

0,1,2,3,4,5,6

};

In addition to the previous codes, D7 is defined as PIN 7 so that the neopixel ring obtains its signals from D7. Moreover, 7 lights from 0-6 are defined.

SoftI2cMaster i2c_1(sda_1, scl_1); MLX90615 mlx90615_1(DEVICE_ADDR, &i2c_1);

void setup() {

Serial.begin(9600);

Serial.println("Setup...");

strip.begin();

strip.setBrightness(20);

strip.show();

}

In addition to previous codes, the brightness of the neopixel ring is defined. You can alter the brightness by changing the value after strip.setBrightness.

void loop() {

float temperatureObj1 = mlx90615_1.getTemperature(MLX90615_OBJECT_TEMPERATURE);

Serial.print("Temp_1: ");

Serial.print(temperatureObj1);

Serial.print("`C ");

Serial.println("\n=======================================\n\r");

delay (100);

Codes for obtaining temperature

for(int i=0; i<7; i++) {

if (temperatureObj1 > 23 && temperatureObj1 < 24) {

strip.setPixelColor(sine[0],strip.Color(128, 128, 128));

strip.show(); }

This means that if temperatureObj1, obatined by sensor 1, falls between 23 and 24, light number 1 (indicated by [0] will show the RGB color (128,128,128). No other lights would be affected. If you want to add sensors/lights, you add numbers to temperatureObj1 (e.g. temperatureObj2) and setPIxelColor(sine[0]) (e.g. setPixelColor(sine[1]).

Similar conditions are repeated but the corresponding temperatures and RGB values would vary. You can create your own colors, but the following full code shows a "rainbow" from purple to red depending on the temperature.

if (temperatureObj1 > 24 && temperatureObj1 < 25) {

strip.setPixelColor(sine[0],strip.Color(102, 102, 153));

strip.show(); }

if (temperatureObj1 > 25 && temperatureObj1 < 26) {

strip.setPixelColor(sine[0],strip.Color(102, 0, 204));

strip.show(); }

if (temperatureObj1 > 26 && temperatureObj1 < 27) {

strip.setPixelColor(sine[0],strip.Color(51, 51, 204));

strip.show(); }

if (temperatureObj1 > 27 && temperatureObj1 < 28) {

strip.setPixelColor(sine[0],strip.Color(0, 0, 255));

strip.show(); }

if (temperatureObj1 > 28 && temperatureObj1 < 29) {

strip.setPixelColor(sine[0],strip.Color(51, 153, 255));

strip.show(); }

if (temperatureObj1 > 29 && temperatureObj1 < 30) {

strip.setPixelColor(sine[0],strip.Color(102, 255, 255));

strip.show(); }

if (temperatureObj1 > 30 && temperatureObj1 < 31) {

strip.setPixelColor(sine[0],strip.Color(102, 255, 204));

strip.show(); }

if (temperatureObj1 > 31 && temperatureObj1 < 32) {

strip.setPixelColor(sine[0],strip.Color(0, 255, 0));

strip.show(); }

if (temperatureObj1 > 32 && temperatureObj1 < 33) {

strip.setPixelColor(sine[0],strip.Color(102, 255, 51));

strip.show(); }

if (temperatureObj1 > 33 && temperatureObj1 < 34) {

strip.setPixelColor(sine[0],strip.Color(204, 255, 51) );

strip.show(); }

if (temperatureObj1 > 34 && temperatureObj1 < 35) {

strip.setPixelColor(sine[0],strip.Color(255, 255, 0));

strip.show(); }

if (temperatureObj1 > 35 && temperatureObj1 < 36) {

strip.setPixelColor(sine[0],strip.Color(255, 204, 0));

strip.show(); }

if (temperatureObj1 > 36 && temperatureObj1 < 37) {

strip.setPixelColor(sine[0],strip.Color(255, 153, 0));

strip.show(); }

if (temperatureObj1 > 37 && temperatureObj1 < 38) {

strip.setPixelColor(sine[0],strip.Color(255, 51, 0));

strip.show(); }

if (temperatureObj1 > 38 && temperatureObj1 < 39) {

strip.setPixelColor(sine[0],strip.Color(204, 51, 0));

strip.show(); }

if (temperatureObj1 > 39 && temperatureObj1 < 40) {

strip.setPixelColor(sine[0],strip.Color(255,0,0));

strip.show(); }}

Step 11: 3 Neopixel Lights With 3 Sensors

This code is to extend the previous code to three sensors. In this code below, the sensors are attached to D2, D3 and D4, which have corresponding SDA and SCL numbers. The same code is repeated, except that the numbers are changed to indicate a second/third sensor/neopixel light. Because the coding for this is replicating the previous steps with small alterations and is also extremely long, I will be including the code under a separate document under the title Code: 3 Neopixel Lights With 3 Sensors.

Step 12: Potential Challenges

There are a few potential challenges that you would face so far.

First, because array values start at 0, you must make sure that you name your lights 0-6 instead of 1-7.

Secondly, make sure that your cords correspond to the correct places and are tightly plugged in. Wires of the neopixel ring tend to not fit very well in the Base Shield.

Thirdly, you can change your object temperature to ambient temperature if 1) sensors do not work as sometimes obtaining object temperature is inconsistent 2) you wish to know changes in temperature of the environment instead of the actual sensor, which increases the sensitivity.

Lastly, make sure that you know clearly what each variable (such as temperatureObj1) means in terms of individual sensor because you need to correspond light with the temperature of a direction a sensor points to.

Step 13: Integrate 7 Sensors With 7 Lights on Neopixel Ring!

Lastly, you can plug all sensors into available ports on the Base Shield. You replicate the previous code for 1 sensor for another 4 times with minor editions, and you would get a neopixel ring that shows the temperature in 7 different directions. You can see how the colors change depending on heat source (hand) on the photos. Moreover, to make the device more sensitive (to changes in temperature potentially caused by a fire, Obj is changed to Amb in the codes, detecting ambient, environment temperature than object, sensor temperature). The extensive code for this will be included in a separate file.

Step 14: Reflections

This project is not only aiming to create a practical device. It incorporates skills that could be used in many other areas: for example, you can obtain the amount of gas if you know how to obtain temperature. Or you can use arrays to program a 64-bit RGB light strip. The skills used to build this project are extremely applicable in other fields, which can be useful in future projects. I believe that my project is overall successful, despite it does not necessarily goes on a straight line before reaching the goal. Taking steps and building mini-devices were needed to thoroughly understand each and every step, which utilizes knowledge from different fields of Arduino programming.

Surprisingly, the biggest challenges encountered are caused by the smallest errors, such as the incorrect "&" or naming the lights 1-7. Moreover, I realized that while object temperature requires less power, ambient temperature makes the device more sensitive, which is better for serving the final purpose. The lesson is that when building codes, every single detail and choice matters.

Even though I believe that the learning purposes of this project is fully achieved, if I were to do this project differently, I hope to incorporate even more elements, such as a buzzer that makes a sound in face of high degrees of temperature increases, with the purpose of enhancing the device's functional purposes.