🧪
Workshops : Arduino
Created
May 26, 2020
Category
🧪 Workshop
Platform
Arduino
Author
Description

AWS1 - Arduino Workshop Intro

Today we kicked our HCI day off with some Arduino basics. While I was trying to get my setup running again and Visual Studio Code kept me busy with SSH connecting loops, , during the course we learned more about basics such as the crucialty of resistors, proper circuits.
 
Wait, which SSH loops - Why Visual Studio Code for Arduino?

My Arduino board is connected to a Banana Pi with VS Code server

Owning one of the newer MacBooks that were designed for bad typing experience, noisy fans and the minimal possible port(un)availability I am facing unusual challenges. Also due to the fact I fried one of my ports once before I became rather cautious about this device and using offbrand-adapters.
Having that challenge combined with the assumption, we would work on that project in a group setting and would need to collaborate, I followed a different approach from the beginning
 
🔧Remote development with Arduino + your favourite micro computer (e.g. Raspberry Pi)
 
 

Prototyping with TinkerCAD

  • So far, I had minor issues where the circuit did not work although copied 1:1 from another setup. What I was trying to do is to copy a setup, adjust the code and have 2 similar setups next to each other. I was messing around for 20 minutes until I realized it can only be fixed by building it again from scratch. Some information might get lost in the clipboard (JSON, whatever)
 

Create & Share

 
Constraints and

Constraints and chances

In the last assignment I found that TinkerCAD had no preset for the LED matrix module with socket (4 cables). However a TinkerCAD community member uploaded an alternative approach for that
 
 

Learnings

  • Only pins with strikes are capable of doing Pulse With Modulation (PWM) and thus can be used to dim LEDs
  • PIN13 is linked to the internal LED - So adressing the internal LED also triggers PIN 13

AWS1 Assignment / Deliverables

Arduino workshop 1: 3C, 4C, 6C, 7C

AWS1 - 3C - BlinkMultiple

I was aiming to make the code more scalable, but it turned out I was lacking a basic certain logic as the LEDs were not working at the same time
Partially working solution (Code)
/*
  Blink

  Turns an LED on for one second, then off for one second, repeatedly.

  Most Arduinos have an on-board LED you can control. On the UNO, MEGA and ZERO
  it is attached to digital pin 13, on MKR1000 on pin 6. LED_BUILTIN is set to
  the correct LED pin independent of which board is used.
  If you want to know what pin the on-board LED is connected to on your Arduino
  model, check the Technical Specs of your board at:
  https://www.arduino.cc/en/Main/Products

  modified 8 May 2014
  by Scott Fitzgerald
  modified 2 Sep 2016
  by Arturo Guadalupi
  modified 8 Sep 2016
  by Colby Newman

  This example code is in the public domain.

  http://www.arduino.cc/en/Tutorial/Blink
*/

// the setup function runs once when you press reset or power the board
void setup() {
  // initialize digital pin LED_BUILTIN as an output.
    pinMode(13, OUTPUT); //Green LED
    pinMode(12, OUTPUT); //Yellow LED

}

// the loop function runs over and over again forever
void loop() {
    blinkLED(12,1000);
}

void blinkLED(int pinNum, int blinkDuration) {
    digitalWrite(pinNum, HIGH);
    offLED(pinNum, blinkDuration);
    pinNum=pinNum+1;      
    blinkDuration=blinkDuration/2;                
    offLED(pinNum, blinkDuration/2);                      

}
void offLED(int pinNum,int blinkDuration){

    delay(blinkDuration);                       // wait for a second
    digitalWrite(pinNum, LOW);


}
Working solution (Code)
/*
  Blink

  Turns an LED on for one second, then off for one second, repeatedly.

  Most Arduinos have an on-board LED you can control. On the UNO, MEGA and ZERO
  it is attached to digital pin 13, on MKR1000 on pin 6. LED_BUILTIN is set to
  the correct LED pin independent of which board is used.
  If you want to know what pin the on-board LED is connected to on your Arduino
  model, check the Technical Specs of your board at:
  https://www.arduino.cc/en/Main/Products

  modified 8 May 2014
  by Scott Fitzgerald
  modified 2 Sep 2016
  by Arturo Guadalupi
  modified 8 Sep 2016
  by Colby Newman

  This example code is in the public domain.

  http://www.arduino.cc/en/Tutorial/Blink
*/

// the setup function runs once when you press reset or power the board
void setup() {
  // initialize digital pin LED_BUILTIN as an output.
    pinMode(13, OUTPUT); //Green LED
    pinMode(12, OUTPUT); //Yellow LED

}

// the loop function runs over and over again forever
void loop() {
    blinkLED();
}


void blinkLED() {
    digitalWrite(13, HIGH);  
    digitalWrite(12, HIGH);      
    delay(500);                       
    digitalWrite(13, LOW);  
    delay(500);
    digitalWrite(13, HIGH);  
    digitalWrite(12, LOW);  
    delay(500);
    digitalWrite(13, LOW);  
    delay(500);
}
 

AWS1 - 4C - FadeLEDAnalog

The solution was pretty straight forward and did not require a second for loop as expected. Negating the value for the second LED was sufficient.
Working solution (Code)
int greenLedPin = 10; int yellowLedPin = 9;
void setup() {
     pinMode(greenLedPin, OUTPUT);
     pinMode(yellowLedPin, OUTPUT);
}
void loop() { 
    for (int brightness=0; brightness <256; brightness++){
         analogWrite(greenLedPin, brightness);
         analogWrite(yellowLedPin, brightness*-1); //negate value of brightness for reverse fade
         delay(10);
    }
}

AWS1 - 6C - FadeLEDPot

 
Working solution (Code)
float sensorValue = 0; // variable for sensor value 
int sensorPin = A0; // variable for sensor pin
int greenLedPin = 10; int yellowLedPin = 9;

void setup() {
    sensorValue = (sensorValue/1023)*255;
    pinMode(sensorPin, INPUT);
    Serial.begin(9600);
    pinMode(greenLedPin, OUTPUT);
    pinMode(yellowLedPin, OUTPUT);

}

void loop() {
    sensorValue = analogRead(sensorPin); // read the value/voltage on the sensor pin and // store that value in the variable sensorValue
    sensorValue = (sensorValue/1023)*255;
    analogWrite(greenLedPin, sensorValue);
    analogWrite(yellowLedPin, sensorValue*-1);
    Serial.println(sensorValue); // print out sensorValue to the Serial Monitor
    delay(200); // delay for 0.2 seconds
}

AWS1 - 7C - LEDMatrixPot

This assignment I wanted to use to use other approaches for saving LED definitions. I chose to follow the process of using uint64_t hashes defined in an array in the beginning of the code instead of byte code. (As described here https://xantorohara.github.io/led-matrix-editor/#3c7ec3c300666600|c3e77e3c00666600)
 
 
Working solution (Code)
#include "LedControl.h"
/*
DIN connects to pin 12 CLK connects to pin 11 CS connects to pin 10
*/
LedControl lc = LedControl(11,10,9,1);

/*
const byte IMAGES[][8] = {
{
  B00000000,
  B01100110,
  B01100110,
  B00000000,
  B11000011,
  B11000011,
  B01111110,
  B00111100
},{
  B00000000,
  B01100110,
  B01100110,
  B00000000,
  B00111100,
  B01111110,
  B11100111,
  B11000011
},{
  B00000000,
  B01100110,
  B01100110,
  B00000000,
  B00000000,
  B11111111,
  B11111111,
  B00000000
}};

const int IMAGES_LEN = sizeof(IMAGES)/8;
*/

// As described in https://xantorohara.github.io/led-matrix-editor/#3c7ec3c300666600|c3e77e3c00666600|0000000000666600
const uint64_t IMAGES[] = {
  0x3c7ec3c300666600,
  0xc3e77e3c00666600,
  0x00ffff0000666600
};
const int IMAGES_LEN = sizeof(IMAGES)/8;

void setup() {
    lc.shutdown(0,false); // Turn matrix on, no power saving 
    lc.setIntensity(0,8); // Set brightness to a medium value 
    lc.clearDisplay(0); // Clear the display
    Serial.begin(9600); 
}



void displayImage(uint64_t image) {
  for (int i = 0; i < 8; i++) {
    byte row = (image >> i * 8) & 0xFF;
    for (int j = 0; j < 8; j++) {
      lc.setLed(0, i, j, bitRead(row, j));
    }
  }
}
int i = 0;

void loop(){
    int sensorValue = analogRead(A0); // read sensor, 0-1023 
    Serial.println(sensorValue);
    sensorValue = map(sensorValue, 0, 1000, 0, 7);
    // remap the value 0-7. (1000 eliminates noise)
    /* Map an analog value to 8 bits (0 to 255)
    Parameters

    value: the number to map.
    fromLow: the lower bound of the value’s current range.
    fromHigh: the upper bound of the value’s current range.
    toLow: the lower bound of the value’s target range.
    toHigh: the upper bound of the value’s target range.

    
     */

    if (sensorValue>6){
        displayImage(IMAGES[0]);

    }else if (sensorValue>3){
        displayImage(IMAGES[2]);

    }else{
        displayImage(IMAGES[1]);
    }
    lc.clearDisplay(0); // Clear the display 

}

AWS2 - Arduino advanced - LED Matrixes and more

 

AWS2 - 9B - PiezoMelody

I already did the same with my ESP8266 but made it again to have the portfolio complete.
 
Working solution (Code)
int speakerPin = 8;
void setup() { 
    pinMode(speakerPin, OUTPUT);
}
void loop() { 
    tone(speakerPin, 262, 200); 
    tone(speakerPin, 294, 200); delay(250);
    tone(speakerPin, 330, 200); delay(250);
    tone(speakerPin, 262, 200); delay(500);
delay(250);
}
 
 

AWS2 - 9D - PiezoInstrument

Great application case to use the map function again - one line but very powerful. (For demonstration purposes I lowered the range for the video to 600, as this reflected the current light in my room)
An additional idea would be to find the current light value in the setup section and set it as range, so pressing the reset button would allow to setup and use the instrument in a different light setting.
Working solution (Code)
int sensorValue = 0; // variable for sensor value 
int sensorPin = A0; // variable for sensor pin
int speakerPin = 8; // variable for sensor pin

void setup() {
    pinMode(sensorPin, INPUT); 
    Serial.begin(9600);
}

void loop() {
    int sensorValue = analogRead(A0); 
    sensorValue = map(sensorValue, 0, 1000, 100, 2000);
    //mapping to freq range 

    Serial.println(sensorValue);
    tone(speakerPin, sensorValue, 200);
    delay(250);
    noTone(speakerPin);
    delay(100);
}
 

AWS2 - 10D - TempSense / HumidSense + Matrix

I can't figure out know where my temparature sensor went - but I added the code as it should work using the suggested analog sensor. What I had flying around however was a DHT11 sensor which features humidity detection as well. With the whole corona aerosol awareness going onI was very curious on making my "invisible" droplets visible just by breathing towards the sensor.
The results are shocking.
Working solution (Code)
#include <dht.h>
#include <MD_MAX72xx.h>

dht DHT;

#define DHT11_PIN 7
//int sensePin = A0;  //This is the Arduino Pin that will read the sensor output
//int sensorInput;    //The variable we will use to store the sensor input
//double temp;        //The variable we will use to store temperature in degrees. 


// Define the number of devices we have in the chain and the hardware interface
// NOTE: These pin numbers will probably not work with your hardware and may
// need to be adapted
#define HARDWARE_TYPE MD_MAX72XX::PAROLA_HW
#define MAX_DEVICES	4

#define CLK_PIN   11  // or SCK
#define DATA_PIN  10  // or MOSI
#define CS_PIN    9  // or SS

MD_MAX72XX mx = MD_MAX72XX(HARDWARE_TYPE, DATA_PIN, CLK_PIN, CS_PIN, MAX_DEVICES);
#define  DELAYTIME  100  // delay between animations in milliseconds

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

}

void loop()
{
 /* sensorInput = analogRead(A0); //read the analog sensor and store it
  temp = (double)sensorInput / 1024;   //find percentage of input reading
  temp = temp * 5;                     //multiply by 5V to get voltage
  temp = temp - 0.5;                   //Subtract the offset 
  temp = temp * 100;                   //Convert to degrees 
  Serial.print("Current Temperature: ");
  Serial.println(temp); */
  
  int chk = DHT.read11(DHT11_PIN);
  Serial.print("DHT11 Temperature = ");
  Serial.println(DHT.temperature);
  Serial.print("DHT11 Humidity = ");
  Serial.println(DHT.humidity);
  float humidityValue = DHT.humidity;
  displayRow(humidityValue);
  delay(2000);


}

void displayRow(float humidityValue){
  humidityValue = map(humidityValue, 50, 100, 0, 7);
  Serial.print("Displayed humidity ");
  Serial.println(humidityValue);
  mx.clear();
  for(humidityValue<7;humidityValue--;){
    mx.setRow(humidityValue,0xff);
  }

}
 

AWS2 - 11D - SocialDistance

As the LED Matrix was still connected, I decided to use it for the distance sensor (Would consider it more visible and clear as well )
 
Working solution (Code)
#include <MD_MAX72xx.h>
const int echoPin = 6; 
const int trigPin = 7;
//int ledPin = 8;

#define HARDWARE_TYPE MD_MAX72XX::PAROLA_HW
#define MAX_DEVICES	4

#define CLK_PIN   11  // or SCK
#define DATA_PIN  10  // or MOSI
#define CS_PIN    9  // or SS

MD_MAX72XX mx = MD_MAX72XX(HARDWARE_TYPE, DATA_PIN, CLK_PIN, CS_PIN, MAX_DEVICES);
#define  DELAYTIME  100  // delay between animations in milliseconds

void setup() {
     pinMode(echoPin, INPUT);
     pinMode(trigPin, OUTPUT);
     Serial.begin(9600); 
     //pinMode(ledPin, OUTPUT);
    mx.begin();

}

void loop() {
    // send a pulse 
    digitalWrite(trigPin,LOW);
    delayMicroseconds(2);
    digitalWrite(trigPin,HIGH);
    delayMicroseconds(5);
    digitalWrite(trigPin,LOW);
    // wait for the echo
    long duration = pulseIn(echoPin, HIGH);
    // convert the time into a distance, the speed of sound is 29 microseconds per centimeter,
    //the pulse traveled forth and back, so we divided the distance by 2
    int cm = duration / 29 / 2; 
    Serial.print(cm);
    Serial.println();
    displayRow(cm);

    delay(100); 
}

void displayRow(int distanceValue){
  distanceValue = map(distanceValue, 2, 150, 7, 0);
  Serial.print("Displayed VALUE ");
  Serial.println(distanceValue);
  mx.clear();
  if(distanceValue>6){

    mx.setRow(0,B10011001);
    mx.setRow(1,B10011001);
    mx.setRow(2,B10011001);
    mx.setRow(3,B10011001);
    mx.setRow(4,B10011001);
    mx.setRow(5,B10011001);
    mx.setRow(6,B00000000);
    mx.setRow(7,B10011001);

        delay(1000);

    }
  for(distanceValue<7;distanceValue--;){
    mx.setRow(distanceValue,0xff);
  }

    
}
 

AWS3 - Making sense of Data + Servo magic

 
In the third workshop we made the first move towards getting data out of the Arduino environment.
 
Just as the console in JavaScript, the Arduino has a serial output monitor.
In the assignment we connected this serial output to Processing, which we got to be using in the programming bootcamp back in 2018.
 
As I am running a slightly different setup at home (See: 🔧Remote development with Arduino + your favourite micro computer (e.g. Raspberry Pi)) ., with the Arduino not being physically connected to my Laptop I was thinking about a different approach on making the data available.
This however tuned out to be beyond the scope of this workshop so I hooked up the Arduino to my laptop.

AWS3 Deliverables

Arduino workshop 3: 12E, 13E, 14C, 15C
 
 

AWS3 - 12E - ProcessingOutput

After hurdles in the beginning (I was trying to gather data from the Arduino connected to my Raspberry Pi), I decided to connect it straight to my computer. I used the distance sensor and slightly modified the Processing file so it shows a blue sign with "AFSTAND HOUDEN", but only when you get close. Funny, right?
 
Working solution (Code) - Arduino
const int echoPin = 6; 
const int trigPin = 7;
float sensorValue;

void setup() {
     pinMode(echoPin, INPUT);
     pinMode(trigPin, OUTPUT);
     Serial.begin(9600); 
     //pinMode(ledPin, OUTPUT);

}

void loop() {
    // send a pulse 
    digitalWrite(trigPin,LOW);
    delayMicroseconds(2);
    digitalWrite(trigPin,HIGH);
    delayMicroseconds(5);
    digitalWrite(trigPin,LOW);
    // wait for the echo
    long duration = pulseIn(echoPin, HIGH);
    // convert the time into a distance, the speed of sound is 29 microseconds per centimeter,
    //the pulse traveled forth and back, so we divided the distance by 2
    int cm = duration / 29 / 2; 
    Serial.println(cm);
    delay(100); 
}
Working solution (Code) - Processing
import processing.serial.*;
Serial myPort;
String sensorReading="";

void setup() {
  size(400, 400);
  myPort = new Serial(this, Serial.list()[4], 9600); 
  // instead of 5, choose what everserial port the Arduino connects to
  myPort.bufferUntil('\n'); }
  
  void draw() {
  int sensorReadingNum = Integer.parseInt(sensorReading.trim());  
  int sensorReadingNeg =   (sensorReadingNum*-1)+200;

  background(255);
  
  fill(0,128,255);
  textSize(12);

  text("Sensor Reading: " + sensorReading, 20, 20);
  
  rectMode(CENTER);
  rect(width/2, height/2, float(sensorReadingNeg*2), float(sensorReadingNeg), 9);
  textSize(32);
  fill(255, 255, 255);
  textAlign(CENTER);{

  if(sensorReadingNum<20) {
  text("AFSTAND HOUDEN!", width/2, height/2);}

    }
  }
  void serialEvent (Serial myPort) { sensorReading = myPort.readStringUntil('\n');
}
 

AWS3 - 13E - TwoButtons

The solution was pretty straight forward and did not require a second for loop as expected. Negating the value for the second LED was sufficient.
 
Working solution (Code)
/*
  Button

  Turns on and off a light emitting diode(LED) connected to digital pin 13,
  when pressing a pushbutton attached to pin 2.

  The circuit:
  - LED attached from pin 13 to ground
  - pushbutton attached to pin 2 from +5V
  - 10K resistor attached to pin 2 from ground

  - Note: on most Arduinos there is already an LED on the board
    attached to pin 13.

  created 2005
  by DojoDave <http://www.0j0.org>
  modified 30 Aug 2011
  by Tom Igoe

  This example code is in the public domain.

  http://www.arduino.cc/en/Tutorial/Button
*/

// constants won't change. They're used here to set pin numbers:
const int buttonPinL = 2;     // the number of the pushbutton pin
const int buttonPinR = 3;     // the number of the pushbutton pin
const int ledPin =  13;      // the number of the LED pin

// variables will change:
int buttonStateL = 0;         // variable for reading the pushbutton status

int buttonStateR = 0;         // variable for reading the pushbutton status

void setup() {
  // initialize the LED pin as an output:
  pinMode(ledPin, OUTPUT);
  // initialize the pushbutton pin as an input:
  pinMode(buttonPinL, INPUT);
  pinMode(buttonPinR, INPUT);

}

void loop() {
  // read the state of the pushbutton value:
  buttonStateL = digitalRead(buttonPinL);
  buttonStateR = digitalRead(buttonPinR);

  // check if the pushbutton is pressed. If it is, the buttonState is HIGH:
  if (buttonStateL == HIGH || buttonStateR == HIGH) {
    // turn LED on:
    digitalWrite(ledPin, HIGH);
  } else {
    // turn LED off:
    digitalWrite(ledPin, LOW);
  }
}

AWS3 - 14C - ServoKnob

The solution was pretty straight forward and did not require a second for loop as expected. Negating the value for the second LED was sufficient.
 
Working solution (Code)
/*
 Controlling a servo position using a potentiometer (variable resistor)
 by Michal Rinott <http://people.interaction-ivrea.it/m.rinott>

 modified on 8 Nov 2013
 by Scott Fitzgerald
 http://www.arduino.cc/en/Tutorial/Knob
*/

#include <Servo.h>

Servo myservo;  // create servo object to control a servo

int potpin = 0;  // analog pin used to connect the potentiometer
int val;    // variable to read the value from the analog pin

void setup() {
  myservo.attach(9);  // attaches the servo on pin 9 to the servo object
}

void loop() {
  val = analogRead(potpin);            // reads the value of the potentiometer (value between 0 and 1023)
  val = map(val, 0, 1023, 0, 160);     // scale it to use it with the servo (value between 0 and 180)
  myservo.write(val);                  // sets the servo position according to the scaled value
  delay(15);                           // waits for the servo to get there
}
 

AWS3 - 15C - CapaTouch

I was really excited about this assignment as it could play an interesting role in a project I was thinking about for a while now.
By the way I have to mention this: Installing libraries with the arduino-cli (command line interface) is so satisfying
Whatever I was trying, it was not possible for me to retrieve a value. I tried another power supply, different pins and asked my peer review partner to share his wiring.
 
Valid code, but not working (Arduino)
#include <CapacitiveSensor.h>
CapacitiveSensor touchSwitch = CapacitiveSensor(4, 2);

int LEDpin = 11;
void setup(){ 
    pinMode(LEDpin, OUTPUT); 
    Serial.begin(9600);
}

void loop()
    {
    long start = millis();
    long val = touchSwitch.capacitiveSensor(30);

    if (val > 100) {
    digitalWrite(LEDpin, HIGH);
    } else {
    digitalWrite(LEDpin, LOW);
    }
    // print sensor output 1
    Serial.println(val);
}
 
After a certain amount of time I realised that the project, I had in mind I wanted to create based on ESP32 hardware anyway (due to some perks such as WiFi and BLE and thus decided to do some research on how to implement a capacitive sensor there.
Eventually I found out that the ESP32 chip in general has pins for 10 touch points (my particular board model has 6. as some are reserved by the OLED screen)
Valid code, working (ESP32S)
void loop() {
  Serial.println(touchRead(T2));  // get value of Touch 2 pin = GPIO 2 / T2
  delay(1000);
  ArduinoOTA.handle();
  //runLED();

}

AWS3 Bonus (Or tinkering? Whatever)

Come on, dispense my pills finally.

Further thoughts

The Emotional Matrix

I was playing around before with displaying different text across the 8x32 Matrix module so never tried to adress just one piece of the panel. To my surprise, all of the modules were adressed, however with a bit of latency between them.

From Input to output

 
"If you understand an example, use it. If you don't understand an example, don't use it."
 

Switching devices

As I was lacking a few cables in comparison to the official HHS Arduino kit, I made an unusual decision.
More cables would have been 5 Euros - but hey , why would I pay 5 Euros if I could also get the Cables + ESP8266 (Whatever it might be, it says WiFi - maybe a WiFi chip?) + OLED Display + a small bread board + a BMP280 (better temperature / humidity sensor than the basic ones + a fancy USB cable) for 17 Euros?
After talking to a friend in the mean time, I realised this was not just a WiFi chip but basically a fully mature, programmable microcomputer, just as the Arduino - but way smaller and thus even better suited for... What are we doing here? True, wearable prototyping! It is running on 3.3V though, so fine for most of the stuff but something to keep in mind.
So I carried on with the Arduino IDE but soon realised the integration was not as smooth as I expected.
The NodeMCU with ESP8266 chip requires some additional libraries and works with different pin names
And well, this was the only thing I needed to carry on with basically the same Arduino code. The only thing to take into account basically was the PIN-mapping.

Input to output, next level