In this workshop you will learn:

This workshop is broken down into a few phases:

Download and install the Arduino IDE Click the JUST DOWNLOAD link to the left of the CONTRIBUTE & DOWNLOAD button. Once downloaded follow the instructions to install.

Create an account on GitHub if you don't already have one.

Get a git client. If you are comfortable using Git on the command line then go for it. If you prefer a GUI representation then download a git client to make your life easier. We use Tower which has a free version for students. We also hear good things about SourceTree and there are a few other open source GUI Clients here

First launch the Arduino IDE. The screenshot below (from a Mac) shows an overview of the main elements of the Arduino 2.0 IDE you will work with today.

Arduino 2.0 IDE Screenshot

The screenshot below (from a Mac) shows an overview of the main elements of the Arduino 1.8 IDE. The notes in red highlight the main elements of the top navigation, the main body of the code and the message window at the bottom.

Arduino 1.8 IDE Screenshot

If you expand the File and Tools main menus. In the File menu Arduino ships with a bunch of useful examples to get you started and to help you explore. In the Tools menu there are a couple of menu items that you will need to get familiar with: the Board item shows you which kind of Arduino you are currently trying to program (in the case below an Arduino Uno WiFi Rev2) and the Port item which shows you which USB port the device is connected to. In this case it is showing the port on a mac at /dev/cu.usbmodem14302 - if I was on a Windows machine it might say COM4.

Arduino Menus Screenshot

In the new IDE you can also use the quick drop down to select your board.

Arduino Menus Screenshot

Further resources on the v2.0 IDE are available on the Arduino IDE 2 Tutorials page if you want to do a deeper dive into what is where.

In the next step we will upload are first Sketch and get the Arduino doing something for us.

To familiarise yourself with the Arduino platform load a basic blink sketch from the examples that are distributed with the Arduino IDE.

First off - plug in your Arduino to a USB port!
Arduino Board

Load the following sketch:
File -> Examples -> Basics -> Blink

Ensure board set to the Arduino you are using (e.g. Arduino Uno):
Tool -> Boards -> Arduino SAMD boards -> Arduino MKR1000

Ensure the correct port for the Arduino Uno has been selected:
Tools -> Port:... as shown in the screenshot below for Windows:

and for Mac:

Note that the your board may connect on a different COM port to the one shown in the screenshot above (COM7) and will be called Arduino MKR1000 (not Leonardo).

Now save and upload the sketch using the upload button (as shown below).

If you look at the Arduino board you should see the built in LED blinking every second.

Arduino Blinking

Next up we will run through the anatomy of a sketch (the setup and the loop) and then return to a bit of house keeping and work out where to store code on our own computers and in the cloud.

The light is flashing, but what was going on?

The beauty of microcontrollers are the simplicity of how programmes run. All Arduino sketches have two primary sections - void setup() which is executed once as the device is powered up, and void loop() which the continually runs until power is removed. Once the code within the latter function gets to the bottom it simply returns back to the start of the function and starts again - hence the name loop.

We look at each in turn:

void setup() {
  pinMode(LED_BUILTIN, OUTPUT);
}

In your blink sketch setup() calls just one function pinMode(). This function defines whether a pin you are connecting to is either an input or an output.

LED_BUILTIN is a variable within Arduino that defines which PIN the onboard LED is on. Traditionally this was on PIN 13 but some newer boards use PIN 6. To make it easier to manage this variable is defined by the board configuration so we don't have to think about it.

OUTPUT means that PIN is acting as an output ie current flows through it to drive an LED.

void loop() {
  digitalWrite(LED_BUILTIN, HIGH);   // turn the LED on (HIGH is the voltage level)
  delay(500);                       // wait for a second
  digitalWrite(LED_BUILTIN, LOW);    // turn the LED off by making the voltage LOW
  delay(500);                       // wait for a second
}

In the loop() function we have 4 steps:

  1. the digitalWrite() function changes a digital pin with a value of HIGH or LOW. In this case we are setting the pin located at LED_BUILTIN (digital pin 13 on the Uno) to a value of HIGH. This sets the voltage level high and ‘turns on' the LED.
  2. the delay() function pauses the sketch for a defined number of milliseconds. In this case we are pausing for 500 milliseconds, or half a second.
  3. the value of LED_BUILTIN is now being set to LOW. This ‘turns off' the LED.
  4. finally we have another pause of half a second.

At the end of the loop() function the program returns back to the start of the loop() function and repeats. The structure of all sketches follow the same pattern.

The beauty of Arduino is there are loads of examples on the internet for you to experiment with. Most things you can imagine have probably already been implemented.

The Arduino IDE can be configured using the preferences section of the application. Equally if you have another code editor of choice they often have plugins to support Arduino sketch development. The Arduino page here has some guidance on tweaking your environment.

The last thing we encourage you to think about at this stage in setting up your Arduino coding environment is the location where you will store files. By default Arduino stores files in your /Documents folder on a Mac or /My Documents folder on Windows and then in a subfolder called /Arduino. It is worth thinking about how you will organise and back up all your code through the rest of the year.

** I am not advising you structure your code like this, am just showing you how I have been doing it for past 15 years! And yes it is in a Dropbox folder, and yes most of this is also on GitHub, and yes it mirrors across my 2 machines at home and work (and even the iPad)

Now that the housekeeping is sorted we can return to making some lights flash. Make sure your Arduino code you have been working on is in the folder you set-up in the previous step (or if you want to start fresh open up the blink example File>Examples>01.Basics>Blink and save a copy of it in your folder).

In our initial sketch we flashed a builtin LED on pin 13. Next we will start using the Pins on the Arduino to prototype our own circuit. The Arduino has a number of exposed female pins that allow you to quickly and easily plug in wires to connect sensors or actuators. A key part of the process of prototyping with microcontrollers is getting familiar with the input and output pins on the board you are using. As an example the standard Arduino has both digital and analog pins as shown in the diagram below from the Introduction to the Arduino Board webpage.

The green pins are digital (can be set hi or low). The blue ones are analog (using a 10-bit analog to digital converter reading a voltage between 0V and either 3.3V or 5V - hence converting to 0 to 1023 or 2^10). The orange ones are power and ground.

You will notice the diagram shows the board having 5V and 9V. This is due to it being an image of an early board and highlights an important lesson:

For example, in setting up this tutorial an Arduino MKR1000 was used and the reference sheet found by googling arduino pin layout mkr1000 and if you compare the two diagrams you will notice some differences.

Whilst the BUILTIN LED is great for debugging and checking the state of programmes, we want to flash a ‘real' LED.

The simplest way we can do this is to add an LED directly into the pins. The positive of the LED goes into PIN13 the negative needs to go to GND or ground which is conveniently located alongside.

Upload the blink sketch to the board and you should now see the LED flashing. LED not flashing? Two things you can check are at the bottom of the page.

In future workshops we will delve into LEDs in more detail and will caution about short circuits etc. But for now you have completed the Hello Word of physical computing!

LED not flashing? This could either be because you have the long and short legs of the LED in the wrong pins, or you have defined your LED to be LED_BUILTIN rather than specifying a pin. Note ‘LED_BUILTIN' on the MKR1000 is ‘13'.

void setup() {
  // initialize digital pin LED_BUILTIN as an output.
  pinMode(LED_BUILTIN, OUTPUT);
}

// the loop function runs over and over again forever
void loop() {
  digitalWrite(LED_BUILTIN, HIGH);   // turn the LED on (HIGH is the voltage level)
  delay(1000);                       // wait for a second
  digitalWrite(LED_BUILTIN, LOW);    // turn the LED off by making the voltage LOW
  delay(1000);                       // wait for a second
}

Correct version when LED plugged into pin 13 and GND is:

void setup() {
  // initialize digital pin LED_BUILTIN as an output.
  pinMode(13, OUTPUT);
}

// the loop function runs over and over again forever
void loop() {
  digitalWrite(13, HIGH);   // turn the LED on (HIGH is the voltage level)
  delay(1000);                       // wait for a second
  digitalWrite(13, LOW);    // turn the LED off by making the voltage LOW
  delay(1000);                       // wait for a second
}

In this section we will connect your board to the UCL_IoT wifi network. Note that we are not connecting to Eduroam but a specific wifi access point that has been setup for IoT devices.

To access this network you will need a specific password for your specific board. We identify your unique board by it's MAC Address The image below of the MKR1000 shows my board has a MAC Address: F8F005EA6143

Fill out this Google Sheet to get your password.

To get started we will use a handy example in the Wifi101 library.

File > Examples > Wifi101 > SimpleWebServerWifi

Once you have your password you can enter in your connections into the arduino_secrets.h file. This is a handy way of being able to use .gitignore to NOT upload your plaintext password to GitHub (and therefore the internet). We can do a whole lecture on IoT security if you are interested!

For the ssid enter: UCL_IoT

#define SECRET_SSID "UCL_IoT"
#define SECRET_PASS "your-password-from-google-sheet"

The main .ino file is hopefully reasonably self explanatory - a quick over is broken down below:

Includes your password file so that you can hide your password.

#include "arduino_secrets.h" 
///////please enter your sensitive data in the Secret tab/arduino_secrets.h
char ssid[] = SECRET_SSID;        // your network SSID (name)
char pass[] = SECRET_PASS;    // your network password (use for WPA, or use as key for WEP)

We define a variable to hold the status of the webserver, initialise it and declare a webserver on port 80.

int status = WL_IDLE_STATUS;
WiFiServer server(80);

In the setup we define an LED pin we want to control (make sure to add an LED to pin 9 - long leg to pin 9 short leg to the GND pin).

We initialise the wifi and try to connect to the network. We don't leave this loop until we are connected. Once we are we then print out some info on the connection. Most importantly we print out the IP address the device is given. The printWiFiStatus function is defined further down in the code.

void setup() {
  ...
  pinMode(9, OUTPUT);      // set the LED pin mode

  // check for the presence of the shield:
  if (WiFi.status() == WL_NO_SHIELD) {
    Serial.println("WiFi shield not present");
    while (true);       // don't continue
  }

  // attempt to connect to WiFi network:
  while ( status != WL_CONNECTED) {
    Serial.print("Attempting to connect to Network named: ");
    Serial.println(ssid);                   // print the network name (SSID);

    // Connect to WPA/WPA2 network. Change this line if using open or WEP network:
    status = WiFi.begin(ssid, pass);
    // wait 10 seconds for connection:
    delay(10000);
  }
  server.begin();                           // start the web server on port 80
  printWiFiStatus();                        // you're connected now, so print out the status
}

In the main loop we are:

void loop() {
  WiFiClient client = server.available();   // listen for incoming clients

  if (client) {                             // if you get a client,
    Serial.println("new client");           // print a message out the serial port
    String currentLine = "";                // make a String to hold incoming data from the client
    while (client.connected()) {            // loop while the client's connected
      if (client.available()) {             // if there's bytes to read from the client,
        char c = client.read();             // read a byte, then
        Serial.write(c);                    // print it out the serial monitor
        if (c == '\n') {                    // if the byte is a newline character

          // if the current line is blank, you got two newline characters in a row.
          // that's the end of the client HTTP request, so send a response:
          if (currentLine.length() == 0) {
            // HTTP headers always start with a response code (e.g. HTTP/1.1 200 OK)
            // and a content-type so the client knows what's coming, then a blank line:
            client.println("HTTP/1.1 200 OK");
            client.println("Content-type:text/html");
            client.println();

            // the content of the HTTP response follows the header:
            client.print("Click <a href=\"/H\">here</a> turn the LED on pin 9 on<br>");
            client.print("Click <a href=\"/L\">here</a> turn the LED on pin 9 off<br>");

            // The HTTP response ends with another blank line:
            client.println();
            // break out of the while loop:
            break;
          }
          else {      // if you got a newline, then clear currentLine:
            currentLine = "";
          }
        }
        else if (c != '\r') {    // if you got anything else but a carriage return character,
          currentLine += c;      // add it to the end of the currentLine
        }

        // Check to see if the client request was "GET /H" or "GET /L":
        if (currentLine.endsWith("GET /H")) {
          digitalWrite(9, HIGH);               // GET /H turns the LED on
        }
        if (currentLine.endsWith("GET /L")) {
          digitalWrite(9, LOW);                // GET /L turns the LED off
        }
      }
    }
    // close the connection:
    client.stop();
    Serial.println("client disonnected");
  }
}

The function below is a nice way to abstract out the information we want to print that tells us about the connection. For example, once we know the IP address

void printWiFiStatus() {
  // print the SSID of the network you're attached to:
  Serial.print("SSID: ");
  Serial.println(WiFi.SSID());

  // print your WiFi shield's IP address:
  IPAddress ip = WiFi.localIP();
  Serial.print("IP Address: ");
  Serial.println(ip);

  // print the received signal strength:
  long rssi = WiFi.RSSI();
  Serial.print("signal strength (RSSI):");
  Serial.print(rssi);
  Serial.println(" dBm");
  // print where to go in a browser:
  Serial.print("To see this page in action, open a browser to http://");
  Serial.println(ip);
}



While you are waiting for everyone to complete this task why not try and add some more information or styling to your page. Have a go at editing these lines.

// the content of the HTTP response follows the header:
client.print("Click <a href=\"/H\">here</a> turn the LED on pin 9 on<br>");
client.print("Click <a href=\"/L\">here</a> turn the LED on pin 9 off<br>");

Hint: think of these lines as the window where you can add in any HTML instructions.

Next up we are going to connect up a TMP36 to measure Temperature. In your kit look for the TMP36, get a few jumper cables and your proto board so that you can wire up the circuit.

TMP36 sensor

Using the TMP36 is easy, with the flat surface of the TMP36 towards you, simply connect the left pin to power (2.7-5.5V) and the right pin to ground. Then the middle pin will have an analog voltage that is directly proportional (linear) to the temperature. The analog voltage is independent of the power supply.

To convert the voltage to temperature, simply use the basic formula:

Temp in °C = [(Vout in mV) - 500] / 10

So for example, if the voltage out is 1V that means that the temperature is ((1000 mV - 500) / 10) = 50 °C

Add the TMP36 to your circuit using the image below as a guide

TMP36

With the flat surface of the TMP36 towards you the left leg connects to VCC, the middle terminal is connected to A0 pin and the other right terminal is connected to Ground.

If you're using a 3.3V Arduino, and connecting the sensor directly into an Analog pin, you can use these formulas to turn the 10-bit analog reading into a temperature:

Voltage at pin in milliVolts = (reading from ADC) * (3300/1024)

This formula converts the number 0-1023 from the ADC into 0-53300mV (= 3.3V)

Then, to convert millivolts into temperature, use this formula:

Centigrade temperature = [(analog voltage in mV) - 500] / 10

The sketch below will shows a complete sketch to read from the TMP36.

/*
 Circuit:
 * TMP36 middle pin attached to pin A0, left to VCC, right to GND

 created Feb 2023
 by Duncan Wilson
 */

#define debugSerial Serial

//TMP36 Pin Variables
int sensorPin = A0; //the analog pin the TMP36's Vout (sense)

void setup() {
  debugSerial.begin(9600);      // initialize serial communication
}

void loop() {
  //getting the voltage reading from the temperature sensor
  int reading = analogRead(sensorPin);  

  // converting that reading to voltage, for 3.3v arduino use 3.3
  float voltage = reading * 3.3;
  voltage /= 1024.0; 

  // now print out the temperature
  float temperatureC = (voltage - 0.5) * 100 ;  //converting from 10 mv per degree wit 500 mV offset
                                                //to degrees ((voltage - 500mV) times 100)
  debugSerial.print(temperatureC); debugSerial.println(" degrees C");

  delay(1000);                                     //waiting a second
}

In the last part of this workshop we are going to focus on getting measurements to the outside world. To do this we will be sending data to an MQTT server.

We are going to pull together the previous Arduino sketches into a final project called BIOS0031tmp36MQTT - the full code for this example is on GitHub. Remember we learn through doing so don't just copy paste - work through the description below - but open up that GIST in a seperate tab so that you can see the full code.

Since we are ‘building' on the shoulders of giants, someone has already written a great MQTT library we can use to do a lot of the connection setup. We will be using the ArduinoMqttClient library. It should be installed but if not go to library panel and install it.

To start, create a new blank sketch. To be able to access others code we need to include their libraries at the start of the sketch. We will also set-up the user names and passwords for the wifi access point and the mqtt broker.

#include <SPI.h>
#include <WiFi101.h>
#include <ArduinoMqttClient.h>
#include "arduino_secrets.h" 

const char* ssid     = SECRET_SSID;
const char* pass     = SECRET_PASS;
const char* mqttuser = SECRET_MQTTUSER;
const char* mqttpass = SECRET_MQTTPASS;

You will notice we are not storing the actual passwords here. We use an #include "arduino_secrets.h" file to store the usernames and passwords - this is so that we can use gitignore to exclude adding those files to the GitHub repository.

To add the arduino_secrets.h file to your code click on the little arrow at the top of the sketch and add new tab as per image below.

Arduino add tab

Then add in the four #defines... lines with the real user names and passwords. For the mqtt_server we will be using mqtt.cetools.org and the student user account (password on whiteboard).

#define SECRET_SSID "xxx"
#define SECRET_PASS "xxx"
#define SECRET_MQTTUSER "xxx"
#define SECRET_MQTTPASS "xxx"

Jumping back to the main .ino tab we will continue to add in / go through rest of the code.

Similar to the WiFi101 in the previous example we need to define a MqttClient that will handle the MQTT messages. Note it passes in the WiFiClient defined as the connection.

We also set-up the address of the broker, the port it communicates on (we are using 1884 which requires a username and password) and the topic we are going to publish our message to.

WiFiClient wifiClient;
MqttClient mqttClient(wifiClient);

const char* broker = "mqtt.cetools.org";
int        port     = 1884;
const char topicTMP36[]  = "student/BIOS0031/ucjtdjw/temperature";

int status = WL_IDLE_STATUS;
WiFiServer server(80);

In the setup function we call two sub functions:

setupWiFi();
setupMQTT();

Hopefully the purpose of these is obvious, setupWifi we have seen before, setMQTT is below. The setId function declares a unique Id for the connection with the MQTT broker - change the value in the code below so that it references your student id (since that should be unique to you). We then execute the connect function passing in user and password. If a connection is established then all is good and we carry on, if not the program stops here in an endless while loop (1 is always True in Arduino speak).

void setupMQTT() {
  Serial.print("Attempting to connect to the MQTT broker: ");
  Serial.println(broker);

  // You can provide a unique client ID, if not set the library uses Arduino-millis()
  // Each client must have a unique client ID
  mqttClient.setId("ucjtdjwBIOS");

  // You can provide a username and password for authentication
  mqttClient.setUsernamePassword(mqttuser, mqttpass);

  if (!mqttClient.connect(broker, port)) {
    Serial.print("MQTT connection failed! Error code = ");
    Serial.println(mqttClient.connectError());

    while (1);
  }

  Serial.println("You're connected to the MQTT broker!");
  Serial.println();  
}

In the main loop we call the function poll to avoid being disconnected by the broker:

mqttClient.poll();

And every time period (defined by variable interval) we execute the code that gets a temperature reading getTempC which should be familiar amd then we have 3 new lines of code where we send that value to the MQTT broker:

mqttClient.beginMessage(topicTMP36);
mqttClient.print(temperatureC);
mqttClient.endMessage();

Save, compile and upload this updated sketch. If you open up the Serial Monitor you should see connection information and then every interval a new temperature reading being takem.

On the next page we will connect to the MQTT server to check for messages coming from the device and to send messages to it.

Your data is being sent to an MQTT broker but how can you see if it is getting there? The simplest way is to use an application that connects to the same broker and subscribed to your topic.

We use a tool called MQTT Explorer and recommend you download and install it! But if you already use another similar tool then stick with that.

Open up MQTT Explorer or similar client. Create a new connection to the MQTT server using:

You can leave the user name and password blank. We have configured this server to allow public viewing privilages to all data (however you need to have an account to publish to this server - hence using port 1884 and a user/pass in the sketch).

MQTT Explorer

Under the topic student you should see all messages since MQTT explorer default to showing all topics using the syntax /# (the /# means subscribe to all information that is sent to the topic).

MQTT Explorer

You can also look at the graphs on Grafana on the Raspberry Pi in the lab username and password are admin admin (please dont change these!)

More information on syntax for topic names and topic filters is available in the awesome documentation.

Computing is all about abstraction and decomposition, breaking tasks into small pieces to help make the overall picture easier to understand. Libraries are essentially programmes that other people have written so that you don't have to repeat what they have done, you can just start to work with their tools.

If you browse to the Arduino Libraries reference you will see examples of where people have already written code so that you don't have to - for example, most sketches I wrote over the past year used the WiFi NINA library.

To install third party Libraries follow the guide on the Arduino reference page. We are particularly fond of the Adafruit NeoPixels Library

— End of Workshop —

You should now have an Arduino sketch saved somewhere locally on your computer. The next stage is to share it online so that others can comment or commit to your project. For example, in Connected Environments we share our code repositories on a CE GitHub.

As an example the repo below shows basic instructions and the code needed to build a RPi that can pull data from a Things Network MQTT feed and push it into a MySQL database on the RPi.

The Intro to GitHub page gives a great overview of the basic features, using the Hello World instructions set-up a code repository with a README file.

Create a repo similar to this:

Following the GitHub Hello World example create a test repository and edit the readme file to say something along the lines of "This is a test repository for a CE lab - I am editing the readme via the web interface."

[Cloning, Editing and Pushing]

You can work directly on the files in the browser (sometimes easier if you are doing something simple like editing the README file) but for work flow most people download a client such as Tower mentioned in the Prerequisites. In this next step we will clone a repository to our local code file store, edit our local copy of the readme file and then push that back to GitHub.

First browse to your repo on Github, click the clone or download button on and copy the link to the repository.

Then open up your client app on your local machine (screenshots below for Tower on a Mac):

At the very bottom left of the screen is a + button to add a new repository. We have one setup on Github so we need to select the clone repository option. On selecting this a dialogue will appear; copy in a link to you repo, add in your github credentials and select the location on your desktop where you want to store your files.

Once cloned if you open up your repository you should see a screen similar to below and if you browse to the folder location you specified to clone to, you should see a local copy of all the files.

Similar to the ‘Intro to GitHub' above you now have access to a number of pull and push features that we will explore over the next few weeks. Each client will have their own tutorials such as this tutorial on Tower.

As a first step you could try editing your README file and then pushing it to the Master on Github. Using your text editor of choice (vi, nano, textedit, sublime, vscode, atom, notepad++ etc.) open the README file on your local machine and edit it with something like "This is a test repository for a CE lab - which was edited originally via the web interface, and now I am editing the readme via my local copy." Save the file and then go back to your Git client.

Click on working copy and you should see the file you have just edited. In the screenshot below I have selected the file, added an update title and some description text. Click Commit when done.

This has saved the "Commit" to your local branch (probably called "main") of the repository but not to the remote version. To do this you need to Push your branch - select the main branch and the HEAD which represents your last changes and then click the Push button (highlighted in red on Tower for Mac below). A dialog will pop up asking if you want to Push the Head.

Now when you head back to GitHub on the web you should see your local copies have meen synchronised with those on the server.

You can either keep the test repository there for posterity or feel free to delete it - we will not be using it again in the course.

Whilst connecting directly into the pin sockets can be done, someone, somewhere, invented the really useful breadboard, which the ultrasonic rangefinder is plugged into in the image above. The breadboard essentially allows you to wire together circuits. To understand how they work it is worth seeing inside one:

As you plug in cables into the holes of the board you can make electrical connections - hence circuits.