Skip to main content

Input Devices

Group assignment:

  • Probe an input device(s)'s analog and digital signals
  • Document your work on the group work page and reflect on your individual page what you learned

Individual assignment:

  • Measure something: add a sensor to a microcontroller board that you have designed and read it.

Step response

I've been pretty impressed by Neil's step response presentation. So I wanted to quickly try it.


source Robert Hart

So I reproduce this schematic from Robert Hart's tutorial with an XIAO ESP32C3 and a breadboard. The only difference is that I use the 3,3V instead of 5V.

picture of breadboard

Here is the quick setup.

I then push this Arduino code on the board. It's a modification of Adrian Torres from Robert Hart. I just changed the pin and comment the remap function to get the raw data.

//tx_rx03  Robert Hart Mar 2019.
//https://roberthart56.github.io/SCFAB/SC_lab/Sensors/tx_rx_sensors/index.html

//Modified by Adrián Torres Omaña
//Fab Academy 2021
//Step Response TX, RX
//Adrianino
//ATtiny1614

// Program to use transmit-receive across space between two conductors.
// One conductor attached to digital pin, another to analog pin.
//
// This program has a function "tx_rx() which returns the value in a long integer.
//
// Optionally, two resistors (1 MOhm or greater) can be placed between 5V and GND, with
// the signal connected between them so that the steady-state voltage is 2.5 Volts.
//
// Signal varies with electric field coupling between conductors, and can
// be used to measure many things related to position, overlap, and intervening material
// between the two conductors.
//


long result; //variable for the result of the tx_rx measurement.
int analog_pin = A0; // the A0 pin ADC of the XIAO ESP32C2
int tx_pin = TX; // the TX pin of the XIAO ESP32C2
void setup() {
pinMode(tx_pin,OUTPUT); //Pin 2 provides the voltage step
Serial.begin(115200);
}


long tx_rx(){ //Function to execute rx_tx algorithm and return a value
//that depends on coupling of two electrodes.
//Value returned is a long integer.
int read_high;
int read_low;
int diff;
long int sum;
int N_samples = 100; //Number of samples to take. Larger number slows it down, but reduces scatter.

sum = 0;

for (int i = 0; i < N_samples; i++){
digitalWrite(tx_pin,HIGH); //Step the voltage high on conductor 1.
read_high = analogRead(analog_pin); //Measure response of conductor 2.
delayMicroseconds(100); //Delay to reach steady state.
digitalWrite(tx_pin,LOW); //Step the voltage to zero on conductor 1.
read_low = analogRead(analog_pin); //Measure response of conductor 2.
diff = read_high - read_low; //desired answer is the difference between high and low.
sum += diff; //Sums up N_samples of these measurements.
}
return sum;
} //End of tx_rx function.

void loop() {
result = tx_rx();
//result = map(result, 8000, 11000, 0, 1024); //I recommend mapping the values of the two copper plates, it will depend on their size
Serial.println(result);
delay(100);
}

Here is a video of it in action. It's pretty clear when I just touch the two plates. But when I add the sponge is harder to see the difference. For that application, I may need to remap the values. The minimum value is ~9200 and the maximum value ~408600. With the sponge in between it's ~375000.

Visualize with Processing

As I want to visualize this data, I took a look at Processing.

Once downloaded and installed. I try the code from Adrian Torres. But first, I added this line on the ESP32C3: result = map(result, 9200, 408600, 0, 1024) to have a better remap for my setup.

//Fab Academy 2021 - Fab Lab León
//Step Response
//Adrianino
//ATtiny1614

import processing.serial.*;

float sensorValue; //variable for the serial data
Serial myPort;

void setup() { //as dynamic/setup function called initially, only once
size(1024, 200);// is the window (1024=sensor max. value)
//replace the port String with the port where your Arduino is connected
//myPort = new Serial(this, "/dev/tty.wchusbserial1450", 115200);
myPort = new Serial(this, "COM7", 115200); // serial port
background(255); //set background white

}

void draw() { //draw function loops

noStroke(); // outline
fill(255,0,0,20); // color inside
rect(0, 0, sensorValue, height); //position and size

fill(255,70);
rect(sensorValue, 0, width-sensorValue, height);

println(sensorValue);
fill(0,0,0);// these are the colors inside
text(sensorValue + " " , sensorValue, height/2);
textSize(32);

}

void serialEvent(Serial myPort) { // sketch read the serial data
String inString = myPort.readStringUntil('\n');
if (inString != null) {
inString = trim(inString);
float[] values = float(split(inString, ","));
if (values.length >=1) {
sensorValue = values[0]; //first value in the list
}
}
}

Really nice to see it graphicly! It gives a lot of ideas.

At the lab, there is a project about a teddy bear that tells stories. For now, it uses buttons underneath the fabric of the teddy bear. But it will be nice to be able to interact with the plush just by touching it. Here is a first try with two pieces of conductive fabric.

Step responses Board with ATtiny412

Update from 13/05/2023

After some comments from Neil I had the idea to do a step response module to get a force sensor. The signal receiver (RX) is on the board, and the sender (TX) is a conductive fabric. The signal is then interpreted and resend through I2C by an ATtiny412.

Here is the Schematic of the board. Nothing special.

For the actual PCB, I change the footprint of the RX pad so it's big enough to receive the signal from the fabric.

I order some vinyl copper sheet, I may finish this little project during the wildcard week. To be continued...

Digital Compas

For the Final Project, it will be nice to have a compass on the screen telling us where the tricycle is going.

For that, I have the SEN0419 DFROBOT module, with the magnetometer BMM150 from Bosch. Here is the Wiki of the module.

So First I need to add the DFROBOT BMM150 Library in Arduino and it should work with my ESP32C3. 🤞

Once done I check the getGeomagneticData example, and took what I needed.

#include "DFRobot_BMM150.h"

DFRobot_BMM150_I2C bmm150(&Wire, I2C_ADDRESS_4);

void setup()
{
Serial.begin(115200);
while(!Serial);
while(bmm150.begin()){
Serial.println("bmm150 init failed, Please try again!");
delay(1000);
} Serial.println("bmm150 init success!");
// Configure Magnometer
bmm150.setOperationMode(BMM150_POWERMODE_NORMAL);
bmm150.setPresetMode(BMM150_PRESETMODE_HIGHACCURACY);
bmm150.setRate(BMM150_DATA_RATE_10HZ);
bmm150.setMeasurementXYZ();
}

void loop()
{
sBmm150MagData_t magData = bmm150.getGeomagneticData();
Serial.print("mag x = "); Serial.print(magData.x); Serial.println(" uT");
Serial.print("mag y = "); Serial.print(magData.y); Serial.println(" uT");
Serial.print("mag z = "); Serial.print(magData.z); Serial.println(" uT");
float compassDegree = bmm150.getCompassDegree();
Serial.print("the angle between the pointing direction and north (counterclockwise) is:");
Serial.println(compassDegree);
Serial.println("--------------------------------");
delay(100);
}


source wiki.dfrobot.com

Let's try this. By default, this module is made to be used in SPI. But it can be used in I²C following this connection.

Here is a video of the data regarding the position of the module. So we can get directly the angle from the North.

Show it on an OLED screen

Time to show it on screen. Following this tutorial, I added my OLED screen to my board and start to add some lines of code.

// include graphical and I²C screen library
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 64 // OLED display height, in pixels
#define OLED_RESET -1
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);

...

void setup() {

...

// SSD1306_SWITCHCAPVCC = generate display voltage from 3.3V internally
if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
Serial.println(F("SSD1306 allocation failed"));
for(;;); // Don't proceed, loop forever
}
display.clearDisplay();
}

It's working!

Now I would love to draw a compass like in this tutorial.

...

const int centreX = 86;
const int centreY = 32;
const int radius = 30;

void loop {
...

display.clearDisplay(); //Clear the Buffer
Draw_Compass();
display.display(); // Must be called to actually print the drawing on screen
}

void display_direction(int x, int y, String dir) {
display.setCursor(x, y);
display.setTextColor(WHITE);
display.setTextSize(1);
display.print(dir);
}

void Draw_Compass() {
int dxo, dyo, dxi, dyi;
display.drawCircle(centreX,centreY,radius,WHITE); // Draw compass circle
for (float i = 0; i <360; i = i + 22.5) {
dxo = radius * cos(i*3.14/180);
dyo = radius * sin(i*3.14/180);
dxi = dxo * 0.95;
dyi = dyo * 0.95;
display.drawLine(dxi+centreX,dyi+centreY,dxo+centreX,dyo+centreY,WHITE);
}
display_direction((centreX-2),(centreY-24),"N");
display_direction((centreX-2),(centreY+17),"S");
display_direction((centreX+19),(centreY-3),"E");
display_direction((centreX-23),(centreY-3),"W");
}

And here we go.

Now let's draw a line that takes the Angle of the Compass from the Magnetometer.

int last_dx, last_dy, dx, dy; // to store ponctual values

void setup {
...
last_dx = centreX;
last_dy = centreY;

}

void loop() {
...
dx = (0.7*radius * cos((compassDegree-90)*3.14/180)) + centreX; // calculate X position for the screen coordinates - can be confusing!
dy = (0.7*radius * sin((compassDegree-90)*3.14/180)) + centreY; // calculate Y position for the screen coordinates - can be confusing!
draw_arrow(last_dx,last_dy, centreX, centreY, 2,2,BLACK); // Erase last arrow
draw_arrow(dx,dy, centreX, centreY, 2, 2,WHITE); // Draw arrow in new position
last_dx = dx;
last_dy = dy;
display.setCursor(0,48);
display.setTextSize(2);
display.print(angle);
display.print(char(247)); // and the degree symbol
display.display();
}

void draw_arrow(int x2, int y2, int x1, int y1, int alength, int awidth, int colour) {
float distance;
int dx, dy, x2o,y2o,x3,y3,x4,y4,k;
distance = sqrt(pow((x1 - x2),2) + pow((y1 - y2), 2));
dx = x2 + (x1 - x2) * alength / distance;
dy = y2 + (y1 - y2) * alength / distance;
k = awidth / alength;
x2o = x2 - dx;
y2o = dy - y2;
x3 = y2o * k + dx;
y3 = x2o * k + dy;
x4 = dx - y2o * k;
y4 = dy - x2o * k;
display.drawLine(x1, y1, x2, y2, colour);
display.drawLine(x1, y1, dx, dy, colour);
display.drawLine(x3, y3, x4, y4, colour);
display.drawLine(x3, y3, x2, y2, colour);
display.drawLine(x2, y2, x4, y4, colour);
}

Here we go, I have a Digital Compass 😄 🧭

Files

Here are the files of the week: