i am playing around with reading values from an FSR. its very simple as of now (code below).
issue that i am facing is that the reading of the values continue to keep climbing they fluctuate up or down but they steadily climb higher. this is opposite of what we saw with Arduino lilypad for the same experiment and generally the same piece of code. readings via lilypad were very stable. once object was placed they stablized and never went up or down until an action was taken with the object.
any idea why?
int fsrAnalogPin = A0;
int fsrReading = 0;
void setup()
{
}
void loop()
{
// sample once per second
delay(1000);
fsrReading = analogRead(fsrAnalogPin);
char s[100];
sprintf(s, "%d", fsrReading);
Particle.publish("Weight Changed", s);
}
The ADC on a photon is different from the kind on an Arduino Uno or lilypad, so your circuit really matters. How do you have it hooked up? In particular do you have another resistor in the circuit?
I am trying to analogRead from a FSR and send the the output through IFTT. This is the code:
const int fsrSensor = A0;
int fsrReading;
int Reading;
int deltaReading;
char* instance1 = "Less than 1oz";
char* instance2 = "Between 1 and 4oz";
char* instance3 = "Between 4 and 10oz";
char* instance4 = "Greater than 10oz";
char* instance5 = "Weight removed...";
void setup() {
Serial.begin(9600);
Reading = analogRead(fsrSensor);
}
void loop(){
fsrReading = analogRead(fsrSensor);
deltaReading = fsrReading - Reading;
static int Case = 0;
if(fsrReading >= 5 && fsrReading <= 50 && Case !=1){
Case = 1;
fsrReading = Reading;
Particle.publish("FSR", instance1, PRIVATE);
delay(10000);
}
else if (fsrReading > 50 && fsrReading <= 150 && Case != 2){
Case = 2;
fsrReading = Reading;
Particle.publish("FSR", instance2, PRIVATE);
delay(10000);
}
else if (fsrReading > 150 && fsrReading <= 350 && Case != 3) {
Case = 3;
fsrReading = Reading;
Particle.publish("FSR", instance3, PRIVATE);
delay(10000);
}
else if (fsrReading > 350 && Case != 4){
Case = 4;
fsrReading = Reading;
Particle.publish("FSR", instance4, PRIVATE);
delay(10000);
}
else if (fsrReading >= 0 && fsrReading < 5 && Case !=5){
Case = 5;
Particle.publish("FSR", instance5, PRIVATE);
delay(10000);
}
delay(3000);
}
If I am on “instance2” and increment slightly the weight, how can I modify the code to notify that “The weight has been increased?” I tried several combinations but no luck!
With IFTTT in order to notify all the instances do I need to create 6 recipes or there is a better and more convenient way?
What does your circuit look like? Do you have a resistive divider with a fixed resistor of a known value and the FSR in series from +3.3V to GND and the analog pin hooked up to the central point? If you just have the FSR connected to the input, it won’t work right. In my tutorial, I used a 1k fixed resistor.
FSR’s are very non-linear devices so building an accurate scale will be challenging. How do you know that the break points you have selected (5,50,150,350) are correct? Have you checked the voltage with a voltmeter under the operating conditions and then calculated (or published see below) what the ADC value should be?
The first sketch I would write would just publish the ADC value every second (the maximum publishing rate) or dump the values to USB serial port or use Tinker as I did in the tutorial so I could record the values under ideal, known weight conditions. That way you can ensure that your break points are all good.
There are many different resistance value FSRs and the one I used was somethingl like 5k with no weight on it, so a 1k fixed resistor was good. If you have 10k FSR, you may need to scale the fixed resistor to make the breakpoints distinguishable.
I appreciate you getting back to me. I really enjoyed reading your tutorial, very interesting!
To answer to your questions:
• The FSR is connected to a voltage divider board using the 2-Pin female cable. The voltage divider board is connected to the Photon with three wires: power (3V3), ground and signal (A0).
I have the flexibility to adjust the resistance.
• I built a mechanical device which allows a uniform and accurate distribution of weight. To test the FSR I sent the values of the analog readings to the terminal. I used a range of known weights, for each of those weights I made several readings positioning the weight on different points of the platform connected to the FSR. For each test-weight (0.5oz, 1oz, 4oz, 10oz) I was able to get a consistent analog reading (most of the time) so knowing the amount of weight I was testing and locking the voltage divider to a specific setting at the beginning of the test I was able to come up with the break points I included in the code. I understand the correlation between force and resistance is non-linear. Based on my test I was able to obtain a consistent range of results which are function of the applied weights.
I am new to programming and I am not quite sure how to achieve the following:
If I am notified by IFTTT that for instance my weight is “Between 1 and 4oz” and there is a slight increment of weight (which does not exceed the breakpoint – 150) I would like to receive a notification saying “More weight has been added…”.
How can I change the code to achieve the above? I tried to write several statements but I had no luck!
If I want to perform more accurate measurement of weights, beside using load cells, are you aware of any cheap component more accurate than the FSR?
OK, it sounds like you have a well-thought-out set up and understand the limitations of FSRs. I will just say that load cells can be cheap too, under $10, and you gain the advantage of the Wheatstone bridge but you would need an op-amp and more external conponents to get that accuracy. Taking apart an electronic scale is a good way to get a cheap load cell.
What you are trying to do is measure change but less than the breakpoints you used. What I would do is keep running average of the last N samples (say 5 or 10) and then when the latest reading exceeds that average by some threshold you must determine, you can send a notice out via a publish string.
Let me try to sketch that out for you (this is untested):
const int fsrSensor = A0;
int fsrReading;
int Reading;
int deltaReading;
int changeThreshold = 25; //I pulled this number out of thin air: you decide
int lastSamples[4]; //four plus the current sample
int lastAverage;
char* instance1 = "Less than 1oz";
char* instance2 = "Between 1 and 4oz";
char* instance3 = "Between 4 and 10oz";
char* instance4 = "Greater than 10oz";
char* instance5 = "Weight removed...";
void setup() {
Serial.begin(9600);
Reading = analogRead(fsrSensor);
}
void loop(){
fsrReading = analogRead(fsrSensor);
deltaReading = fsrReading - Reading;
//I wrote this to be easy to understand, not optimized.
lastAverage = fsrReading + lastSamples[0] + lastSamples[1] + lastSamples[2] + lastSamples[3];
lastAverage = (int)( (float)lastAverage/5.0 ); //not really needed-you can scale threshold instead
for(int ii=0;ii++;ii<3) {
lastSamples[ii] = lastSamples[ii+1]; // move them down
}
lastSamples[3] = fsrReading;
static int Case = 0;
if(fsrReading >= 5 && fsrReading <= 50 && Case !=1){
Case = 1;
fsrReading = Reading;
Particle.publish("FSR", instance1, PRIVATE);
delay(10000);
}
else if (fsrReading > 50 && fsrReading <= 150 && Case != 2){
Case = 2;
fsrReading = Reading;
Particle.publish("FSR", instance2, PRIVATE);
delay(10000);
}
else if (fsrReading > 150 && fsrReading <= 350 && Case != 3) {
Case = 3;
fsrReading = Reading;
Particle.publish("FSR", instance3, PRIVATE);
delay(10000);
}
else if (fsrReading > 350 && Case != 4){
Case = 4;
fsrReading = Reading;
Particle.publish("FSR", instance4, PRIVATE);
delay(10000);
}
else if (fsrReading >= 0 && fsrReading < 5 && Case !=5){
Case = 5;
Particle.publish("FSR", instance5, PRIVATE);
delay(10000);
}
else if ( (fsrReading - lastAverage) > changeThreshold ) {
Particle.publish("FSR","Weight Added", PRIVATE);
}
else if ( (fsrReading - lastAverage) < -changeThreshold) {
Particle.publish("FSR","Weight Removed",PRIVATE);
}
delay(3000);
}
I hope all is well with you. Finally this past weekend I had some time to work on the above topic. FYI I ended up using a configuration of four 1/2 Wheatstone bridge with INA125P circuit amplifier and a pot resistor to tune the gain.
I am getting pretty accurate results, even though every once in a while I noticed there are a couple of erratic readings (mostly when the scale is empty). I do not totally understand why this happens, maybe it has something to do with the wires length connecting the scale to the Photon and to the fact that if they are moved (I am using jump wires at the moment) the resistance may change enough to cause faulty readings.
The code I am using is the following:
#include "math.h"
const int loadPin = A0;
const int numReadings = 800;
int readings[numReadings];
int sIndex = 0;
float sTotal = 0;
float sAverage = 0;
int lastWeight;
int weight;
const float ouceConv = 0.03527396195;
//Load cells calibration
int loadA = 22;
float analogvalA = 112.7;
int loadB = 3985;
float analogvalB = 279.2;
void setup() {
Serial.begin(9600);
}
void loop() {
lastWeight = weight;
weight = loadFunction();
static int Case = 0;
if(weight < 1 && weight > 0 && Case !=1){
Case = 1;
Particle.publish("MNS", "Light weight less than 1 oz.", PRIVATE);
delay(10000);
}
else if (weight >=1 && weight < 16 && Case != 2){
Case = 2;
Particle.publish("MNS", String::format("Weight: %d oz.", weight), PRIVATE);
delay(10000);
}
else if (weight >= 16 && Case != 3) {
Case = 3;
int pounds = floor(loadFunction()/16);
int ounces = loadFunction() - pounds * 16;
Particle.publish("MNS", String::format("Weight: %d lb %d oz.", pounds, ounces), PRIVATE);
delay(10000);
}
else if (weight - lastWeight > 2 && Case != 4){
Case = 4;
int newWeight = lastWeight + (weight - lastWeight);
if (newWeight >= 16){
int newPounds = floor(newWeight/16);
int newOunces = newWeight - newPounds * 16;
Particle.publish("MNS", String::format("More weight added! New weight: %d lb %d oz.", newPounds, newOunces), PRIVATE);
}
else{
Particle.publish("MNS", String::format("More weight added! New weight: %d oz.", newWeight), PRIVATE);
}
delay(10000);
}
else if (weight - lastWeight < -2 && Case !=5){
Case = 5;
Particle.publish("MNS", "The weight has been removed...", PRIVATE);
delay(10000);
}
Serial.print("Average reading: "); Serial.println(sAverage); //For debug....
delay(5000);
}
/*
sTotal = 0;
while(sIndex < numReadings){
readings[sIndex] = analogRead(loadPin);
sTotal = sTotal + readings[sIndex];
sIndex++;
}
if(sIndex == numReadings){
sIndex = 0;
}
sAverage = sTotal / numReadings;
Serial.print("Average reading: "); Serial.println(sAverage);
delay(300);
*/
}
int loadFunction(){
sTotal = 0;
while(sIndex < numReadings){
readings[sIndex] = analogRead(loadPin);
sTotal = sTotal + readings[sIndex];
sIndex++;
}
if(sIndex == numReadings){
sIndex = 0;
}
sAverage = sTotal / numReadings;
int load = analogToLoad(sAverage);
if(load < 0){
load = 0;
}
int loadOunces = load * ouceConv;
return loadOunces;
}
float analogToLoad(float averageLoad){
float load = mapfloat(averageLoad, analogvalA, analogvalB, loadA, loadB);
return load;
}
float mapfloat(float x, float in_min, float in_max, float out_min, float out_max){
return ((x - in_min) * (out_max - out_min) / (in_max - in_min)) + out_min;
}
I am not sure if is the most efficient way to write it, but it works pretty good!