Measuring Force and Displacement with arduino (solved)

For a project I need to measure force and displacement to produce a graph and save the data for later examination at a PC or Android device.
I need to measure the characteristics of spiral springs.

I have a 24 BIT ADC and load cell working for measuring the force. Sketch works fine.
Data can also be displayed at PC side.
Now this was the easy part. :slight_smile:

For the displacement measuring (how far the spring is compressed in relation to the force) I am looking into what might be the best solution and a resolution of 1 mm or less.
Any tips?

Paco

Vernier caliper with digital interface.

This would depend on how large/powerful the springs are and the distance of travel but you could maybe use a simple stepper motor or motor/encoder combination and control/count the number of turns on a threaded bar. It would need something like a micro-switch to act as a home/reference indicator so you know where your starting from.

I will make a manual version first using this device or similar.
http://www.conrad.nl/ce/nl/product/812399/Mobiele-boorgeleider/?ref=detview1&rt=detview1&rb=1
So no motorized version first. :wink:

Can I make the uno become a sliding caliper?

Riva, I need to debug and test code first and in a later stage expand to motorized version.
Springs are between 60 to 150 mm in length and are compressed upto 70 %.
Software at PC side will notify if we pass the preset maximum compression travel.

Paco

Cheap and accurate would be as AWOL suggests, maybe something like this It will interface to an external display so you would need to determine the connection/protocol to interface to your arduino but this article may help.

Riva, there must be a way to make the arduino in a sort of sliding caliper. :grin:
I do not need the 0.01mm resolution of the caliper .
If my data recording gets the force value at every 1 mm of compression the graph would exsist of 30 data points which will give if the spring is progressive more then enough datapoints to create nice curved graphs.
For a motorized version with a threaded shaft a rotary encoder would work, but for this sliding measurement a linear strip should do the job?

I have seen 150 LPI encoder strips available. so 25,4mm devide through 150 gives a lot of data points per mm to measure against or am I thinking wrong way?
I have to check my defective inkjet printer if such strip is available.
Do not know if the arduino can work with the code of the load cell and encoders in one sketch to send the data to the PC.

Paco

so 25,4mm devide through 150 gives a lot of data points per mm

If fewer than six is "a lot", then yes,

If fewer than six is "a lot", then yes,

We are not looking for sientific data :wink:

Currently dismantling my old defective inkjet printer.
I have the 150 Lines per Inch strip now in my hand I have to see if I can get the encoder that comes with it can get to work with the arduino.

Let you know.

Paco

Linear encoder runs fine.
See picture.

Code for load cell and linear encoder seperate work fine.
But when I combine them the linear encoder keeps displaying the 5000 value in the serial monitor.

What do I do worng when I know I almost there in this prototype stage?

Again thanks for the assistance.

Paco

The combined code of load cell and linear encoder:

// Interrupt information optical encoder
// 0 on pin 2
// 1 on pin 3

//default connection arduino NANO/UNO TM7709 24 bit ADC
//DRDY = pin 11 >MOSI
//ADIO = pin 12 >MISO
//SCLK = pin 13 >SCK

//default connection arduino MEGA TM7709 24 bit ADC
//DRDY = pin 21 >MOSI
//ADIO = pin 22 >MISO
//SCLK = pin 28 >SCK

#define TM7710_DRDY        3          
#define TM7710_ADIO        4          
#define TM7710_ADIO_OUT()  DDRB|=1<<4     
#define TM7710_ADIO_IN()   DDRB&=~(1<<4)  
#define Set_TM7710_SCLK()  PORTB|=1<<5
#define Set_TM7710_ADIO()  PORTB|=1<<4
#define Clr_TM7710_SCLK()  PORTB&=~(1<<5)
#define Clr_TM7710_ADIO()  PORTB&=~(1<<4)

unsigned char x[3];
long Result;
float vref=4.57;

int val;
int encoder0PinA = 2;
int encoder0PinB = 3;
int encoder0Pos = 5000;
int encoder0PinALast = LOW;
int n = LOW;

void setup() 
{
  DDRB|=1<<5 ;
  //delay(1000);
  Serial.begin(9600);// set baudrate for PC too!
  TM7710_Init();
 
  pinMode (encoder0PinA,INPUT);
  pinMode (encoder0PinB,INPUT); 
}

void loop()
{  
  double volt = Result * vref /16 / 6.912; 

  while((PINB&(1<<TM7710_DRDY))==(1<<TM7710_DRDY)); 
  TM7710_start();
  TM7710_write(0x7F);        
  TM7710_ADIO_IN();          
  for(unsigned char j=0;j<3;j++)
  
  {
    x[j]=TM7710_read();
  }
  
  TM7710_ADIO_OUT();         
  TM7710_stop();
  Result=x[0];
  Result = Result * 256;
  Result = Result + x[1];
  Result = Result * 256;
  Result = Result + x[2];
  Result = Result - 6912000;

  Serial.print ("A,");
  Serial.println (volt,0);
  
    n = digitalRead(encoder0PinA);
  if ((encoder0PinALast == LOW) && (n == HIGH)) 
  {
    if (digitalRead(encoder0PinB) == LOW) 
    {
      encoder0Pos--;
    } 
    else 
    {
      encoder0Pos++;
    }
    Serial.print ("B,");
    Serial.println (encoder0Pos);

  }
  encoder0PinALast = n;
  
  
}

void TM7710_start(void)   
{
  Clr_TM7710_ADIO();
  delayMicroseconds(1);
  Clr_TM7710_SCLK();
  delayMicroseconds(1);
}

void TM7710_stop(void)    
{
  Clr_TM7710_ADIO();
  delayMicroseconds(1);
  Set_TM7710_SCLK();
  delayMicroseconds(1);
  Set_TM7710_ADIO();
  delayMicroseconds(1);
}

void TM7710_write(unsigned char dd)
{
  unsigned char i; 

  for(i=8;i>0;i--)
  {
    if(dd&0x80)
      Set_TM7710_ADIO();   
    else
      Clr_TM7710_ADIO();   

    delayMicroseconds(1);
    Set_TM7710_SCLK();       
    delayMicroseconds(1);
    Clr_TM7710_SCLK();      
    dd<<=1;                  
  }
}

unsigned char TM7710_read(void)
{
  unsigned char data=0,i; 

  for(i=0;i<8;i++)
  {
    Set_TM7710_SCLK();                   

    data=data<<1;                                  
    if((PINB&(1<<TM7710_ADIO))==(1<<TM7710_ADIO))  
    {
      data=data+1;
    }
    delayMicroseconds(1);
    Clr_TM7710_SCLK();
    delayMicroseconds(1);
  }
  return data;
}

void TM7710_Init()
{
  TM7710_ADIO_OUT();
  delay(100);
  TM7710_stop();
  TM7710_start();
  TM7710_write(0xBF);        
  TM7710_write(0x20); //ADC preamp Gain=128
  TM7710_stop();      
}

I switch on and off part of the code but I get stuck in the fact the load cell code always works.
The linear encoder code only works when the load cell code is switched off. :frowning:

Could the delayMicroseconds(1); invoke problems with the interupt not working?
Should I work with two arduinos to get teh data ported to he PC

BTW the PC part is ready and with some fake files we could produce graphs.
Eager to get the Arduino code to work.

Maybe you need to put the encoder reading into an interrupt so you don't miss edges while reading load cell.

Riva,

Adjusted the code on your advice and bingo…

Works!

Thanks,

Paco

// Interrupt information optical encoder
// 0 on pin 2
// 1 on pin 3

//default connection arduino NANO/UNO TM7709 24 bit ADC
//DRDY = pin 11 >MOSI
//ADIO = pin 12 >MISO
//SCLK = pin 13 >SCK

//default connection arduino MEGA TM7709 24 bit ADC
//DRDY = pin 21 >MOSI
//ADIO = pin 22 >MISO
//SCLK = pin 28 >SCK

#define TM7710_DRDY        3          
#define TM7710_ADIO        4          
#define TM7710_ADIO_OUT()  DDRB|=1<<4     
#define TM7710_ADIO_IN()   DDRB&=~(1<<4)  
#define Set_TM7710_SCLK()  PORTB|=1<<5
#define Set_TM7710_ADIO()  PORTB|=1<<4
#define Clr_TM7710_SCLK()  PORTB&=~(1<<5)
#define Clr_TM7710_ADIO()  PORTB&=~(1<<4)

unsigned char x[3];
long Result;
float vref=4.57;

enum PinAssignments 
{
  encoderPinA = 2,   // rigth
  encoderPinB = 3,   // left
};

volatile unsigned int encoderPos = 5000;  // a counter for the encoder
unsigned int lastReportedPos = 1;   // change management
static boolean rotating=false;      // debounce management

// interrupt service routine vars
boolean A_set = false;              
boolean B_set = false;

void setup() 
{
  DDRB|=1<<5 ;
  //delay(1000);
  Serial.begin(9600);// set baudrate for PC too!
  TM7710_Init();

  pinMode(encoderPinA, INPUT); 
  pinMode(encoderPinB, INPUT); 
  pinMode(clearButton, INPUT);
 // turn on pullup resistors
  digitalWrite(encoderPinA, HIGH);
  digitalWrite(encoderPinB, HIGH);
  digitalWrite(clearButton, HIGH);

// encoder pin on interrupt 0 (pin 2)
  attachInterrupt(0, doEncoderA, CHANGE);
// encoder pin on interrupt 1 (pin 3)
  attachInterrupt(1, doEncoderB, CHANGE);
}

void loop()
{  
  double volt = Result * vref /16 / 6.912; 

  while((PINB&(1<<TM7710_DRDY))==(1<<TM7710_DRDY)); 
  TM7710_start();
  TM7710_write(0x7F);        
  TM7710_ADIO_IN();          
  for(unsigned char j=0;j<3;j++)
  
  {
    x[j]=TM7710_read();
  }
  
  TM7710_ADIO_OUT();         
  TM7710_stop();
  Result=x[0];
  Result = Result * 256;
  Result = Result + x[1];
  Result = Result * 256;
  Result = Result + x[2];
  Result = Result - 6912000;

  Serial.print ("A,");
  Serial.println (volt,0);

  
    rotating = true;  // reset the debouncer

  if (lastReportedPos != encoderPos) {
    Serial.print("B,");
    Serial.println(encoderPos, DEC);
    lastReportedPos = encoderPos;
  }
  if (digitalRead(clearButton) == LOW )  {
    encoderPos = 5000;
  }
  
}

void TM7710_start(void)   
{
  Clr_TM7710_ADIO();
  delayMicroseconds(1);
  Clr_TM7710_SCLK();
  delayMicroseconds(1);
}

void TM7710_stop(void)    
{
  Clr_TM7710_ADIO();
  delayMicroseconds(1);
  Set_TM7710_SCLK();
  delayMicroseconds(1);
  Set_TM7710_ADIO();
  delayMicroseconds(1);
}

void TM7710_write(unsigned char dd)
{
  unsigned char i; 

  for(i=8;i>0;i--)
  {
    if(dd&0x80)
      Set_TM7710_ADIO();   
    else
      Clr_TM7710_ADIO();   

    delayMicroseconds(1);
    Set_TM7710_SCLK();       
    delayMicroseconds(1);
    Clr_TM7710_SCLK();      
    dd<<=1;                  
  }
}

unsigned char TM7710_read(void)
{
  unsigned char data=0,i; 

  for(i=0;i<8;i++)
  {
    Set_TM7710_SCLK();                   

    data=data<<1;                                  
    if((PINB&(1<<TM7710_ADIO))==(1<<TM7710_ADIO))  
    {
      data=data+1;
    }
    delayMicroseconds(1);
    Clr_TM7710_SCLK();
    delayMicroseconds(1);
  }
  return data;
}

void TM7710_Init()
{
  TM7710_ADIO_OUT();
  delay(100);
  TM7710_stop();
  TM7710_start();
  TM7710_write(0xBF);        
  TM7710_write(0x20); //ADC preamp Gain=128
  TM7710_stop();      
}

// Interrupt on A changing state
void doEncoderA(){
  // debounce
  if ( rotating ) delay (1);  // wait a little until the bouncing is done

  // Test transition, did things really change? 
  if( digitalRead(encoderPinA) != A_set ) {  // debounce once more
    A_set = !A_set;

    // adjust counter + if A leads B
    if ( A_set && !B_set ) 
      encoderPos += 1;

    rotating = false;  // no more debouncing until loop() hits again
  }
}

// Interrupt on B changing state, same as A above
void doEncoderB(){
  if ( rotating ) delay (1);
  if( digitalRead(encoderPinB) != B_set ) {
    B_set = !B_set;
    //  adjust counter - 1 if B leads A
    if( B_set && !A_set ) 
      encoderPos -= 1;

    rotating = false;
  }
}

Glad its now working as you expected. Nice hack of the printer encoder BTW.

Here two screenshots of the project in action.
Repeatability is OK now I have to motorize the compression.

Paco

Hello, @backbone, We are working on similar kind of project as yours. Basically we are working on a TENSOMETER apparatus to measure tensile load. So, there will be a material sample instead of spring. So, can you tell me which sensor you used for measuring deflection and also the name of the software you used.

I am working on similar kind of project. I have used a load cell with hx711 amplifier to measure load and a rotary encoder to measure displacement through counting motor rotations. I want to know that which software you have used to plot graphs ? can you provide an arduino code for my project ? Any help will be appriciated...@backbone