Week 11: Input Devices

March 30, 2024

Electronic Design

This week, in the input device project, I tested various sensors on the PCB I designed. I used the MPU6050 - Gyroscope/Accelerometer, TT223 Touch Sensor, HC-SR04 Ultrasonic Sensor, Adafruit MAX4466 - Amplifier, and QRE1113 Line Sensor.

Group Assigment Page

group assignment link 🚀

Greeting KiCad

Alt Text Alt Text

MPU6050 6 Axis Acceleration and Gyro Sensor

Using the MPU-6050 sensor, I embarked on a project to simulate directional movements. Initially, I discovered the necessity to filter the raw data provided by the sensor to enhance accuracy and reliability in the simulations. This process involved adjusting the sensor outputs to mitigate noise and potential distortions.

Furthermore, I learned that the MPU-6050 operates using I2C protocols, which facilitated the communication between the sensor and my microcontroller platform. This knowledge was crucial as it enabled me to effectively integrate the sensor into my system, harnessing its full potential for precise motion detection and orientation tasks.

Alt Text

Code Explanation

Initial Setup

Data Reading

Serial Port Output

Enhancements and Usage

This basic setup forms a solid foundation for developing more complex applications using the MPU6050 sensor for various motion detection and positioning applications.

Code 6050

#include <Wire.h>
#include <I2Cdev.h>
#include <MPU6050.h>

MPU6050 accelgyro;
int16_t ax, ay, az;
int16_t gx, gy, gz;

void setup() {
    Wire.begin();
    Serial.begin(9600);
    Serial.println("Initialize MPU6050");
    
    accelgyro.initialize();
    if (accelgyro.testConnection()) {
        Serial.println("MPU6050 connection successful");
    } else {
        Serial.println("MPU6050 connection failed");
    }
}

void loop() {
    accelgyro.getMotion6(&ax, &ay, &az, &gx, &gy, &gz);

    // Print tab-separated accel/gyro x/y/z values for the Serial Plotter
    Serial.print("Accel: ");
    Serial.print(ax); Serial.print("\t");
    Serial.print(ay); Serial.print("\t");
    Serial.print(az); Serial.print("\t");
    Serial.print("Gyro: ");
    Serial.print(gx); Serial.print("\t");
    Serial.print(gy); Serial.print("\t");
    Serial.println(gz);
    
    delay(100);
}

I need to use the libraries Wire.h, I2Cdev.h, and MPU6050.h for this code. The goal is to read accelerometer and gyroscope data from the sensor using the accelgyro.getMotion6(&ax, &ay, &az, &gx, &gy, &gz) method, and to assign these values to the respective variables. This data is then to be displayed in a simplified tabular format on the port every 100 milliseconds.

TTP223 Touch Sensor

Alt Text

Alt Text

TTP223
#include <Arduino.h>
#include <U8g2lib.h>

#ifdef U8X8_HAVE_HW_SPI
#include <SPI.h>
#endif
#ifdef U8X8_HAVE_HW_I2C
#include <Wire.h>
#endif

// OLED display setup
U8G2_SSD1306_128X64_NONAME_F_HW_I2C u8g2(U8G2_R0);

// Sensor pin
const int touchPin = D10; // TT223B touch sensor pin

void setup() {
  pinMode(touchPin, INPUT); // Set sensor pin as input
  u8g2.begin(); // Start the OLED display
  Serial.begin(9600); // Start serial communication
}

void loop() {
  int touchState = digitalRead(touchPin); // Read digital data from sensor

  u8g2.clearBuffer(); // Clear the screen
  u8g2.setFont(u8g2_font_ncenB08_tr); // Set the font
  u8g2.setCursor(0, 15); // Set the cursor position

  // Display text based on sensor state
  if (touchState == LOW) { // If touched
    u8g2.print("I feel it");
  } else { // If not touched
    u8g2.print("Fab Academy 24 Aalto");
  }

  u8g2.sendBuffer(); // Update the display
  delay(100); // Wait 100 ms
}

My objective with this code is to interact with the display using the D10 pin. When the TT223B touch sensor detects a touch, it reads the digital data from the sensor and displays it on the screen. The messages ‘I feel it’ and ‘Fab Academy 24 Aalto’ on the display change when touched and released, respectively. Additionally, the output can also be viewed on the serial port at 9600 baud. My goal was to demonstrate the interaction between input and output through this setup.

QRE 1113 Line Sensor

Alt Text

#include <Arduino.h>
#include <U8g2lib.h>

#ifdef U8X8_HAVE_HW_SPI
#include <SPI.h>
#endif
#ifdef U8X8_HAVE_HW_I2C
#include <Wire.h>
#endif

// OLED display setup
U8G2_SSD1306_128X64_NONAME_F_HW_I2C u8g2(U8G2_R0);

// Sensor pin
const int QRE1113_Pin = D7; // Connect to digital pin 7

void setup() {
  pinMode(QRE1113_Pin, INPUT); // Initially set as INPUT
  u8g2.begin();
  Serial.begin(9600);
}

void loop() {
  int QRE_Value = readQD();
  Serial.println(QRE_Value); // Output the value to the serial monitor

  u8g2.clearBuffer();
  u8g2.setFont(u8g2_font_ncenB08_tr);
  u8g2.setCursor(0, 15);

  // Determine the message based on sensor reflection
  if (QRE_Value < 300) { // Assuming 300 is the threshold for "on the line"
    u8g2.print("Tracking the line");
  } else {
    u8g2.print("Out of line");
  }

  u8g2.sendBuffer();
  delay(100);
}

int readQD() {
  // Returns value from the QRE1113
  pinMode(QRE1113_Pin, OUTPUT);
  digitalWrite(QRE1113_Pin, HIGH);
  delayMicroseconds(10);
  pinMode(QRE1113_Pin, INPUT);

  long time = micros();
  while (digitalRead(QRE1113_Pin) == HIGH && micros() - time < 3000);
  int diff = micros() - time;

  return diff;
}

I’ve set the initial value using the D7 digital pin. My goal here is to call the readQD function through this digital pin. This sensor measures the amount of reflected light and reads a value. Within this value range, if the value is below 300, it returns ‘Tracking the line’; otherwise, it returns ‘Out of line’. From time to time, I find myself needing to optimize this value. Depending on the ambient light, it is necessary to adjust the value between 250 and 350.

Max4466 Electret Microphone

Alt Text


#include <Arduino.h>
#include <U8g2lib.h>

#ifdef U8X8_HAVE_HW_SPI
#include <SPI.h>
#endif
#ifdef U8X8_HAVE_HW_I2C
#include <Wire.h>
#endif

// OLED display setup
U8G2_SSD1306_128X64_NONAME_F_HW_I2C u8g2(U8G2_R0); // Constructor for hardware I2C

const int micPin = D0;  // The pin where the microphone's output is connected
const int sampleWindow = 50; // Sample window width in mS (50 mS = 20Hz)
unsigned int sample;

void setup() {
  pinMode(micPin, INPUT);
  u8g2.begin();  // Start the OLED display
  Serial.begin(9600);  // Start serial communication for debugging
}

void loop() {
  unsigned long startMillis = millis();
  unsigned int peakToPeak = 0;
  unsigned int signalMax = 0;
  unsigned int signalMin = 1024;

  // Collect data for the set sample window time
  while (millis() - startMillis < sampleWindow) {
    sample = analogRead(micPin);
    if (sample < 1024) {  // ensure the incoming values are valid
      if (sample > signalMax) {
        signalMax = sample;
      } else if (sample < signalMin) {
        signalMin = sample;
      }
    }
  }
  peakToPeak = signalMax - signalMin;  // calculate the peak-to-peak value
  int volume = map(peakToPeak, 0, 512, 0, 64);  // map to a scale of 0-64 for display height

  u8g2.clearBuffer();  // Clear the display buffer
  u8g2.setFont(u8g2_font_6x10_tf);  // Set the font
  u8g2.drawFrame(0, 0, 128, 64);  // Draw a frame for the bar graph

  // Draw the bar graph
  u8g2.drawBox(10, 64 - volume, 20, volume);

  // Display the volume level as a number
  u8g2.setCursor(50, 10);  // Set the cursor position
  u8g2.print("Volume: ");
  u8g2.print(volume);
  
  u8g2.sendBuffer();  // Transfer buffer to the display

  delay(100);  // Refresh every 100 milliseconds
}

This sensor operates on an analog basis. The objective here is to record the lowest and highest sound levels, with the difference between these values providing the peak amplitude of the sound wave. We achieve sound level measurement by this method. We measure the values every 50 milliseconds to perform this process.

Why this sensor analog ?

Analog sensors work by converting sound waves into electrical signals. Since sound waves inherently have a continuous and variable nature, this indicates the necessity of capturing them in an analog format. The analog sensor effectively preserves the integrity and details of these waves, making it suitable for accurately reflecting the nuances of sound.

HC-SR04 Distance Senosr

Alt Text

Code

#include <Arduino.h>
#include <U8g2lib.h>

#ifdef U8X8_HAVE_HW_SPI
#include <SPI.h>
#endif
#ifdef U8X8_HAVE_HW_I2C
#include <Wire.h>
#endif

// OLED display setup
U8G2_SSD1306_128X64_NONAME_F_SW_I2C u8g2(U8G2_R0, /* clock=*/ SCL, /* data=*/ SDA, /* reset=*/ U8X8_PIN_NONE);

// HC-SR04 pins
const int trigPin = D10;
const int echoPin = D7;

long measureDistance() {
  digitalWrite(trigPin, LOW);
  delayMicroseconds(2);
  digitalWrite(trigPin, HIGH);
  delayMicroseconds(10);
  digitalWrite(trigPin, LOW);

  long duration = pulseIn(echoPin, HIGH);
  return duration * 0.034 / 2;
}

// Manual swap function
void swap(long& a, long& b) {
  long temp = a;
  a = b;
  b = temp;
}

// Function to perform a simple bubble sort
void bubbleSort(long arr[], int n) {
    int i, j;
    for (i = 0; i < n-1; i++) {
        for (j = 0; j < n-i-1; j++) {
            if (arr[j] > arr[j+1]) {
                swap(arr[j], arr[j+1]);
            }
        }
    }
}

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

void loop(void) {
  static long distances[5]; // Buffer to store last 5 readings
  static int index = 0;
  long currentDistance = measureDistance();
  
  // Update readings
  distances[index++] = currentDistance;
  if (index >= 5) index = 0;
  
  // Sort distances
  bubbleSort(distances, 5);
  long medianDistance = distances[2]; // Get median value

  // Display and send to serial if reasonable
  if (medianDistance > 0 && medianDistance < 400) {
    Serial.print("Distance: ");
    Serial.print(medianDistance);
    Serial.println(" cm");
    
    u8g2.clearBuffer();
    u8g2.setFont(u8g2_font_ncenB08_tr);
    u8g2.setCursor(0, 15);
    u8g2.print("Distance: ");
    u8g2.print(medianDistance);
    u8g2.print(" cm");
    u8g2.sendBuffer();
  }

  delay(100);  // Adjust delay to manage sensor reading intervals
}

I assigned D10 as the trigPin and D7 as the echoPin for the HC-SR04 ultrasonic distance sensor. This setup allows me to send a pulse with the trig pin and measure the return time with the echo pin after it bounces back. I stored the measured times in an array. The goal was to calculate the median to eliminate fluctuations and obtain more reliable results, particularly for distances under 10 cm. By using a bubble sort, I took the last five measured distances and determined their median value, which I then displayed on the screen. Specifically, I filtered out any values outside the range of 0 to 400 centimeters with the condition if (medianDistance > 0 && medianDistance < 400), thus avoiding displaying erratic, unwanted distances during sudden movements. Another modification was adding a delay before triggering the trig pin, which helped stabilize the triggering times.

Problems ESP

When using the ESP32-C3, I encountered a port error. After extensive research, I found an interesting way to solve it. I press both the R and B buttons simultaneously, then press the B button again, and the device appears. I tested this solution across three operating systems: Linux Ubuntu, macOS Sonoma, and Windows 11, and I encountered the same issue on all of them."

Alt Text

Source Files

Source Folder