ARDUINO For engaging with the physical world

Arduino is designed to experiment with interactivity, art and technology in creative ways. Specifically Arduino is a swish army knife for experimenting with physical computing.

Input and outputs

What makes an Arduino board great is that you can have inputs and outputs. You can read some value from an input (e.g. a button) and then decide to do something with an output (e.g. a led diode).

All the pins with numbers from 0 to 13 and A0 to A5 can be used as digital inputs and outputs. Stay away from pin 0 and 1 because they are also used for communication over USB. To read pin 3 you do the following:

pinMode(3,INPUT_PULLUP);

digitalRead(3);

To set pin 3 you do the following:

pinMode(3,OUTPUT);

digitalWrite(3, HIGH);

Or;

pinMode(3,OUTPUT);

digitalWrite(3, LOW);

(you only need to call pinMode once from setup)

A0 to A5 can also be used as analogue inputs:

analogRead(A0);

The pins with a little "~" can be used as analogue outputs:

analogWrite(11,100);


What setting a pin high or low really means is that it is sending 5V out of the pin or reading whether there is 5V going into the pin.

To start

Arduino IDE

  • Serial monitor is where you can observe the code.

  • Upload code allows you to upload code.

  • Verify code allows you to verify without uploading.

  • The status bar at the bottom informs you of a successful upload.

Serial prompt (or monitor)

The serial monitor gives you clean text as output. This is really useful if you want to know what is going on in your code. You can then send a message back to your computer informing you about something. A simple example:

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

Serial.println("Hello World");
}

The above code will start the monitor with a communication speed of 9600 (notice how the monitor windows have the same speed - important). Then it will send a message saying, "Hello World". This will inform you that your board has started.

This is the serial prompt.

Serial plotter

Instead of receiving clean text, you can also plot your input into a graph to get a better real-time understanding of what is going on.

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

void loop(){
Serial.println(analogRead(A0));
}

The above will constantly read the first analogue port and send it to the plotter.

If you want multiple data points in your plot, you need to separate it with a comma (,) and a linebreak at the end:

void loop(){
Serial.print(analogRead(A0));
Serial.print(",");
Serial.println(analogRead(A1));
}

println vil print it with at linebreak and print will print it without.

This is the serial plotter

setup() and loop()

Setup and loop are the two main functions.

Setup runs once you start the app. This is where you place your code that needs to be run at startup.

void setup() {

//runs once at startup.

}

Loop loops constantly. This is where you place your code that needs to be interactive.


void loop() {

//runs for each frame

}

Notice how the curly brackets define the start and end of each function. This is called a scope, and you will often see this way of grouping code into groups.


The core concepts of programming in Arduino

Most programming languages consists of the same set of elements. Below I try to introduce you to the coding syntax and concepts of them. The core concepts are:

  • Decisions: Making choices on the fly.

  • Scopes: Grouping multiple commands.

  • Memory: A way to store information (variables) dynamically.

  • Repetition: A way to repeat groups of code.

  • Macros: A way to reuse code and structure the logic.

  • Lists: A way to store lists of information.

  • Objects: Grouping information and macros together.

Below I made short videos for each core concept and its syntax.


BasicArduinoProgramming
This google slide presentation on the right presents them in a compressed manner. It is essentially the different concepts and syntax you will typically need to know. You can use it to get an overview of what you need to learn, and also to look up when you are going to write similar code yourself.

Decisions with if statements

Interactive programming is essentially about making decisions. If x happens then do y. The basic syntax making decisions is:

if (2==2) {

Serial.println("this is true");

}

If the condition 2 equals 2 is met then the ellipse will be drawn on the screen.

Further, "else" can be used to execute something if the condition is not met:

if (2==3) {

Serial.println("not true");

} else {

Serial.println("this is true");

}

In the above case 2 is not equal to 3 so the ellipse will not be drawn, but the rectangle will.

Multiple if statements can be combined with "else if":

if (2==2 && 2>1) {

Serial.println("this is true");

} else if (true) {

Serial.println("this will not happen");

} else {


}

Only the first condition which is true will run.

Different formulas can be made with: <, >, ==, != and conditions can be combined with && (and), II (or).

What is the difference between 1/0, HIGH/LOW, true/false? Nothing they are just three different ways to write the same thing so:

0 = LOW = false

1 = HIGH = true

The computer operates in zeros and ones, but sometimes it is more readable to think in terms of a pin being low or high, or something being true or false.


A common mistake is to put a semicolon after if statements. This will not result in an error, but the scope beneath will always execute. Leading to utter confusion. See the following section about commands and scopes.

Grouping commands with scopes

A command is, e.g. when you write Serial.println("xx"); to write into the console. A command typically ends with ";" EXCEPT when it is followed by a scope. E.g.:

Serial.println("hello world");


if(2==2)

{ // start of the scope

Serial.println("Two does equals two");

Serial.println("Second command");

} // end if statement and scope

Notice where the ";" and the curly brackets are placed. The if statements do not have a ";" at the end.

A scope is multiple commands grouped together. Scopes start and end with curly brackets. They define a group of code that is executed when a certain condition is met. In the previous, you learned about if statements. Notice how the scope after the command "if" is only executed when the condition of the if statement is met. And also notice that there is no semicolon at the end of the if statement.

Also, scopes can be nested. A scope can have scope inside itself. This allows conditions to be more complex. E.g. if you are at the supermarket then buy milk if they have a low-fat version. This is two scopes nested inside each other.

if(inSuperMakert==true)

{// first scope start

if(hasLowFatMilk==true)

{ // nested scope

print("buying milk!");

}

}

It can be difficult to wrap your head around this concept. I often wonder if this is the most essential part of being able to program.

Common mistakes and how to fix them

When starting out programming, you will make a few common mistakes. This lists some of them and how to fix them:

  • Forgetting a semicolon: If you forget to put a semicolon at the end of a line, the program will not run. Add the semicolon where missing (usually the line above the one that throws an error).

  • Adding a semicolon after an if statement: There should never be a semicolon after an if statement. This one is hard to detect because the program will run, but it will always run the code inside the curly braces {}.

  • Too many or too few curly braces. Be very careful with your curly braces if you add too many or have too few the program will not run. Make sure to indent your code properly so you are able to read it. Everything inside a curly brace should be indented.

  • Remember to relieve the stress on the cables: Most Arduino projects end up having multiple wires hanging everywhere. If you do not tie them to the board but leave them hanging in the soldering points, they will break. Use a zip tie to mount them to the edge of the board or to the inside of a box.

  • Document your setup: If you do not document your setup you will be in a lot of pain when something falls apart, and you are trying to figure out where e.g. the blue wire was supposed to be connected and whether the red wire is 5v or ground. Use your phone to take pictures of your wiring on a regular basis

Storing information with variables in the memory

A variable is a container of information that can be changed during runtime.

int x = 200;

In the above case we have declared a variable with the name "x" and given it a value of 200. We can then change the value by:

x = 300;

To increment it by one:

x = x+1;

This also increments by one:

x++;

There are different kinds of variable types. They are defined implicitly by adding content to it. E.g. a boolean (true or false) can be defined like this:

boolean playMusic = true;

Through variablesm we can execute different parts of the program with if statements:

if(playMusic == true)

{

// code to play music here

}

If playMusic is true then the code inside the curly brackets will run.

Notice how we use one equal sign (=) when defining variables and two equal signs (==) when comparing a variable to a value.

We typically declare a variable at the top. This way we have global access to them since they are in the global scope. If we place the definition inside e.g. function draw() we will only have access to it inside the scope of the function, and it will be reset every time we run the function.

These are typical variables types:

Repetition with loops

If we want to repeat a piece of code more than once, we can use different kinds of loops to do so. The most common is "for" loops. It is usually used when you have a specific amount of repetition you want to do:

for(int i = 0; i < 10; i = i +1)

{

Serial.println(i);

}

The above code will repeat itself ten times. "i" will be the counter that will increment one for each repetition as long as i is less than 10.

The starting value is zero (a common logic in programming), and the loop will repeat ten times until it reaches 9 (not ten; a common confusion). This is because it only runs as long as it is less than ten.


for(Initialization; condition; incrementation)

A for loop has three parameters separated with a semicolon:

  • Initialization: Sets the initial value.

  • Condition: Choose when to stop the repetition.

  • Incrementation: Defines how much the variable should increment.

Another loop used for repetition is a while loop. The following code will loop endlessly:


while(true)

{

// this loop will repeat itself forever.

}

Read more about for loops here and while loops here.

A for loop can be converted to a while loop. This does the same as the for loop mentioned.

Macros with functions

When programming, you often have a sequence of commands you want to run at different times during the execution of your code. This can be small macros like converting from inches to mm, and it can be more complex elements. These sequences are grouped in function. Let us say that we have an application that often needs to print out a value/variable. Instead of copying Serial.print commands for each situation, we can then make a function and call it multiple times:

void printValue()

{

Serial.println("The value is:");

Serial.println("20");

}

The problem is now that we do not have a way to define the value. We solve this by adding parameters to the function:

void printValue(int value)

{

Serial.println("The value is:");

Serial.println(value);

}

x and y are local variables that we can call like this:

printValue(20)

Functions can also return something. Let's say that we want to have a function the converts from meters to milimeters:

void mToMM(float length)

{

return length*1000;

}


Serial.println(mToMM(10.2f));

Calling mToMM(10.2) will return 10200.

Read more about the use of functions here.

Lists' of variables with arrays

Often one wants to have a list of elements. This can be particles in a particle system or a list of employees in a company. For this to work, we need to group variables together in a list that we can iterate through. This is called an array. An array is a variable containing a list of variables. Square brackets are used to define it as a list:

int values[3];

This is an empty list with six allocated spaces. We can predefine it with content:

int values[] = {3,2,4};

If we want to get the first value:

Serial.println(values[0]);

This prints "3".

If we want to print out all the values in our list, we can use a for loop:

for(int i = 0; i < 3; i=i+1)

{

Serial.println(values[i]);

}

Notice that the for loop repeats until it has reached the length of the list, and the "i" from the for loop is used to retrieve the individual values.

Read more about different types of arrays here.


Objects as a group of functions and variables

This is by far the most complex thing to understand. To simplify, we need to make an analogy. Put simply: I have a Toyota Car. My Toyota is an object like any other object in this world (chairs, gloves, plants). My Toyota is of the classification "car" and not of the type "plant". So if we want to create my car as an object in code, we need to create a classification that we can make it from. Classification can then be used to create an instance as an object (e.g. "my car" is made from the classification "a car").


We define a classification as follows:


class Car

{

public:

int wheels = 0;

String name = "";

int topSpeed = 0;



Car()

{

name="";

wheels=4;

topSpeed=200;

}

};

Notice the function "Car()". This is a special function that constructs the different variables that make up the car. "This" refers to the car class.

If we want to create an instance (object) of the classification car:

Car myCar;

This executes the constructor that defines the variables (name, wheels and topSpeed).

We can then access and change the variables in our newly created car object:

print(myCar.wheels);

This will print the number of wheels (in this case, four).

Let us say that myCar has three wheels then we can set it to three:

myCar.wheels = 3;

The "." is called dot notation and is a central part of many programming languages. Dot notation allows us to access variables inside objects and also objects inside objects, etc.

We can embed functions inside an object like this:

class Car

{

public:

void honk()

{

//Play honk sound here.

}

};

This would be executed by calling:

myCar.honk();

Read more about class and constructors here or here.

(Arduino pin layout)