Week 10 - Input Devices

Assignment

Individual assignment

measure something: add a sensor to a microcontroller board that you have designed and read it

Group assignment

measure the analog levels and digital signals in an input device

Link to group page

Process

Choosing and testing a sensor

In order to make some meaningful steps toward my final assignment, I wanted to test and see a sensor that I could make use for further applications.

That’s I took under my hand a Force Sensitive Resistor, being a sensor that varies in signal according to the pressure over it. Specifically I’ve chosen an SFR 406 by Interlink Technologies that, according to its official datasheet, can weigh from 0 to 10 kg with a 10 gm sensibility.

The first thing I did with it was to test it with a multimeter and see its behaviour. Essentially the FSR is a resistor with infinite ohm unless you apply a force over it, in which case the ohm rises. So, I just connected the multimeter to the two FSR pins (they have no polarity) and pushed over it.

testing SFR

It seemed to work, then I had to make use of it inside a system.

Testing with Arduino

I wanted to proceed in steps, beginning from very easy application, hence I plugged the FSR to an Arduino Nano according to a tutorial I found on Adafruit.

nano setting

I added an extra LED from the aforementioned tutorial, in order to obtain a LED lighting up when a pressure threshold was surpassed and another varying in intesity of light according the amount of pressure (this was done using one of the PMW pin of the board).

Following the same Adafruit tutorial, I adapted a simple code making use of the Arduino library to test various situation. This is the code I uploaded on the Arduino Nano:

int fsrAnalogPin = A1;  // FSR is connected to A1
int LED1pin = D11;      // connect Red LED to D11 (PWM pin)
int LED2pin = D13;      // connect Red LED to D13
int fsrReading;         // the analog reading from the FSR resistor divider
int previousReading = 0;
int LEDbrightness;
int serialThreshold = 20;
int LEDthreshold = 180;
int msWaitingTime = 100;

void setup(void) {
  Serial.begin(9600);
  pinMode(LED2pin, OUTPUT);
  pinMode(LED1pin, OUTPUT);
}
 
void loop(void) {
  fsrReading = analogRead(fsrAnalogPin);

  // control to avoid serial duplicates
  if ((fsrReading < previousReading - serialThreshold) || (fsrReading > previousReading + serialThreshold)) 
  { 
    Serial.print("Analog reading = ");
    Serial.println(fsrReading);
    previousReading = fsrReading;
  }
  
  //map is a function that calculates the proportion of a value from a range to another
  LEDbrightness = map(fsrReading, 0, 1023, 0, 255);

  // LED turns on if you press enough
  if (LEDbrightness > LEDthreshold )
    digitalWrite(LED2pin, HIGH);
   else
    digitalWrite(LED2pin, LOW);
  
  // LED gets brighter the harder you press
  analogWrite(LED1pin, LEDbrightness);

  // delay to avoid serial dumping
  delay(msWaitingTime);
}

By adding few lines to establish a serial communication I would be able to see directly what was going on with the FSR and result was just fine

nano working

Testing with Hello Board

Before heading toward a board of my own design, I wanted to try some use of the sensor with plain C and the avr/io.h library with an already existing board and for this case the customized Hello Board was just fine.

Before doing so, I took a look at the very handful Interlink integration guide which explains how to use and complement the sensor in many situation. Specifically, it explained (perhaps in a way too techcnical way) why I had to set up a voltage divider after the sensor, meaning a resistor connected both to a sensor pin, the GND and the controller pin. This is used to establish the sensor properly and get a reliable signal even in case of no force applied to it.

In the following picture, it’s possible to see the resulting setting with an Arduino Uno that is used just as a programmer.

hello setting

The code that I wrote for this setting I adapted from some of the Neil’s functions from his own examples and my own personal previou experiments. Essentially, the code listens to the sensor and whenever it is pressed the board’s LED lights up

//A code for a blink responding to an FSR pressure
#include <avr/io.h>

#define output(directions,pin) (directions |= pin) // set port direction for output
#define fsr_port PINA
#define fsr_pin 0b01000000
#define LED_MASK 0b00000100

//turn LED according to flag
void LED (_Bool flag) {
   if (flag)
      PORTB = PORTB | LED_MASK;
   else
      PORTB = PORTB & ~LED_MASK;
}

//return 1 if FSR pressed, otherwise 0
_Bool FSR_Pressed()
{
   if ((fsr_port & fsr_pin) == fsr_pin)
      return 1;
   return 0; 
}

int main(void) {
   // initialization
   output(DDRB, LED_MASK);
   LED(0);

   // main loop
      while (1) {
         LED(FSR_Pressed());
      }
      
   return 1; //if reached, a strange, weird error is breathing on your neck 
}

Even in this case, the result was just fine.

hello off

hello on

Since in my Hello Board the LED is not connected to a PWM pin it’s not possible to get a simulated analog response, so it was about time to make a new board.

Brand new board

For my new board what I wanted to accomplish was to have a controller that could handle:

  • Serial communication;

  • SFR analog reading;

  • A voltage divider;

  • Analog and digital LED activation;

Following the principles learned during week 4 and week 6 assignments, to do so I built the whole design on Eagle around an ATtiny 44.

First, I began to add all the elements and to connect all the correlated pins to each other in the schematic editor (as in the previous assignment, I only used Fab and Sparkfun component libraries).

schematic

This was a pretty linear and simple process, for which I only had the follow some directives exposed in the pinout of the ATtiny44 controller

pinout

According to the chart above, if I wanted to make use of the FSR properly I would have to connect it to a pin with the label ADC (Analog-to-Digital-Converter). These pins are those in which an electric analog signal can be properly converted into a usable digital value. As well, to get a proper analog output to run my LED (or anything requiring a discrete value instead of a logical one) I would have had to use any of the pin labeled with PWM (pulse-width-modulation). These are the pins that are able to simulate an analogical signal by sending digital pulses with different duration.

Furthermore, the pinout chart gave all the indications I needed to properly connect oscillator, FTDI and ISP.

Once the schematic was complete, I was ready to design the board.

board

I added a 2-pin clamp for connecting the FSR and slide switch because… it was fancy and I just wanted to reharse a bit more with both Eagle and soldering, and upon our instructor Matteo suggestion I added pin holes for every controller pin left unconnected (just in case I needed them for any purpose).

I was quite proud that the end result required no bridges and 0-ohm resistors, even though it required indeed some headscratching and manipulation of many Eagle parameters such as traces width (down to 10 mils) and clearance length (down to just 164”), but in the end - theoretically - every part should work just fine.

After making the board design, I exported three separated files - traces, holes, and outlines - and modified them on Gimp before feeding them to Fab modules. I open up a little digression on a issue I met using Gimp (but perhaps it can happen in any raster editor) that stumbled upon while working on the Fab modules.

After exporting the PNGs, I wanted to create a trace routing file with 0 offset, so to remove all the useless copper over the PCB, but after several minutes of processing the site didn’t generate yet any file and the preview image looked like nothing was going on.

bad traces

After some inspection (still with Matteo), it resulted not that Fab modules wasn’t working but that I prompted an image more than 10 times larger that what I intended. The other PNGs were as well oddly big, up to several dozens of cm, and totally useless.

What the hell was going on?

It took me several tests to understand it, but in the end I was able to track back the source of the problem in how I opened up my Gimp file in the first place. If you open a new document and then load a PNG on it, if you trim the image surface to only the area you are interested in (like I did), the document mantains the DPI related to the initial document and eventually export your new file with stretched sizes. Instead, if you directly open one of your images and then directly work on that, when exporting the file mantains its initial DPI. It was a trivial and easy to solve issue, but still managed to make me lose a lot of time and could have possibly caused great inconveniences.

After exporting correctly the PNGs, I processed them on Fab modules, obtained my RML files and sent them to the milling machine.

milling

The final drilling didn’t get out very well and I had to brute force a bit the board out of its frame, but it was just it and the soldering process (although not very skilled) went away just fine.

board top

board bottom

A big mistake

After soldering the board, using the Crosspack suite, I wasn’t able to load anything on it. It was a great cause of frustration at first, especially because all the soldering looked just fine, but it was only after several hours, while checking the schematics on Eagle, that I figured I designed a flawed board.

Specifically, I traced the route from the SCK pin of the ISP header to the wrong pin on the micro-controller. This was not an issue I could solve easily, that’s why I opted to to desolder all the component on the board and desing a new one.

desoldering

In this new board, beyond fixing the trace problem, I rearranged a lot of components in a more straight-forward way, so that it could be easier to figure out the place of the components and the soldering process could be a little bit quicker.

new schematics

new board

I was able to recover almost all the components from the previous board, so that overall the process wasn’t a total waste of resource but could instead help me practice more on soldering.

Another big mistake

After milling and soldering the new board, when I flashed it, I was stunned to see that it wasn’t working as well…

After several testing I figured out that I made another silly mistake out of distraction: one of the oscillator pin wasn’t connected in the right place. This was indeed frustrating as before, but at least was a minor inconvenience that I could fix with some wire to make horrible jumpers and obtain a frankenboard.

frankenboard

The result was not good looking but I still wanted to make it work, if it wasn’t for the fact that it didn’t yet!!!

With Avrdude I wasn’t able to flash anything, and this situation got me to the point of full-throttled anger until (upon some more inspection) I realized that I mounted the micro-controller bottomside top…

Along with the osciallator flaw, this realization took me to draw and mill once again a new, better and (hopefully) correct board.

New sensor, new board

Weeks passed and I was still in need of an input board that could make the job that I really wanted. I the meantime I delved more into the world of weight sensors and realized that using an FSR isn’t actually a good choice, if you’re dealing with precise measurements.

That’s how I discovered load bars and figured out that they were the perfect choice especially for my final project. For this reason, I ordered a 10kg load bar and a load cell amplifier from Sparkfun.

bar and amp

Essentially load bars works like this: inside a rigid block there are several wires configured as a Wheatstone bridge and that slightly varies in amp as soon as you strain the block, like applying a force over it. This variation is really, really tiny - to the tune of few milliamps - and so it needs to be amplified and converted into something readable. That’s the purpose of the load cell amplifier when connected to a load bar. The amplifier - in my case a HX711 - can be connected through a two wire serial communication to any two pins of a crontoller and, through the help of handy library on Github, calibrating and reading a load bar becomes the mere works of a couple of functions.

For this purpose I prepared a new board, which I would use in the final project, that could feature the needed requirements to read a load bar.

In the image below, the circled wires are those in the boards devouted to the input sensing.

board

This two pins are connected to the corresponding ones to the load cell amplifier, which is itself connected to the load bar through four colored wires. Every kind of weight sensor has its specific way of being installed, and in my case I had to mount the load bar in a Z configuration between sufraces with the help of bolts and nuts.

load bar

In this way, it is ensured the most reliable strain and measurement of the force.

Before using the sensor in any way, it’s necessary a calibration procedure exposed very well in its related SparkFun tutorial. Basically, you run the provided program on an Arduino and through a serial monitor you adjust the value of the calibration factor until you obtain back the exact wheight of a weight-known load applied to the bar.

calibration

Note that in this way it doesn’t matter if you have some tare standing over the load bar, as long as you don’t change it for later measurements the calibration factor will consider it in its zeroing.

In the case of my project, a calibration factor of 210000 would make the HX711 to prompt a value of 1 for a 1kg load.

Testing

To properly test the functioning of both my board and the load bar, I wrote a simple routine that would nervously flash a led on the board as soon as the bar sense more that half kg of load.

Here’s the code:

#include "HX711.h"

#define led 8

#define DOUT  2
#define CLK  3

HX711 scale(DOUT, CLK);
float calibration_factor = 210000;
int loadAssessment = 50;
float sensorThreshold = 0.50;

void RapidBlink() {
	digitalWrite(led, HIGH);
	delay(50);
	digitalWrite(led, LOW);
	delay(50);
	digitalWrite(led, HIGH);
	delay(50);
	digitalWrite(led, LOW);
	delay(50);
}

bool CheckLoad(float value) {
	delay(loadAssessment); //load assessment delay
	float load = scale.get_units(3); //values up to the third decimal
	if (load > value) {
		return true;
	}
	return false;
}

void setup() {
	pinMode(led, OUTPUT);
	RapidBlink(); //LED test

//Scale zeroing and reset routine
	scale.set_scale();
	scale.tare();
	long zero_factor = scale.read_average();
	scale.set_scale(calibration_factor);
}

void loop() {
	if(CheckForLoad(sensorThreshold)) {
		RapidBlink();
	}
}

Result

In the end, board and sensor worked just as I wanted from them

load bar test video

Here’s the link to the downlads:

Gist & Further development

There’s one thing that I learned for sure, and is that electronic design and production requires a lot of focus and attention. I found myself designing and soldering those flawed boards in moments of tiredness and hurry, and the result was that I lost almost thrice the time intended for these tasks.

It was, however, a good way to learn a harsh lesson and pratice a lot my not so good skills in soldering. Furthermore, the whole process made me think a lot about the many parts that will compose my final project and envision better the steps I’ll have to follow, starting from the input sensors.

Tools and software used