Torque Sensor & Amplifier Current, Interpretation

Hello all,

I believe this is in the right category, please correct me if I'm wrong. I'm a very new to this so I do apologize ahead of time.

So I'm working on a existing projects that uses a stepper motor, torque meter and amplifier which sends a 4-20mA current loop my Arduino screw shield and other components. The signal has been converted to a voltage/digital conversion. The issue that I'm having is that my machine is over torqueing compared to a calibrated torque wrench and calibrated meter. But the value displayed on my LCD Shield says otherwise... (Ex. Torque wrench and meter = 48 in lbs, LCD shield display = 68 in lbs), the higher the torque, the higher the variation. I think that my program may not be interpreting my signal correctly.

I guess I'm just needing help in reading and deciphering what this code really is.
Vcc = 5.0V (Voltage Output)
ADCvalue = (Analog to Digital)???
AfterVolt = ???

 // Read 1.1V reference against AVcc
  ADMUX = _BV(REFS0) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1);
  delay(2); // Wait for Vref to settle
  
  ADCSRA |= _BV(ADSC); // Convert
  while (bit_is_set(ADCSRA,ADSC));
  result = ADCL;
  result |= ADCH<<8;
  result = 1154158L / result; // Back-calculate AVcc in mV
  return result;

void initialStrain() {
       intitalStrainVoltage = 0.0; 
       for (int i=0; i <= 5; i++) { 
       Vcc = readVcc()/1000.0;
       ADCValue = analogRead(strainPin);
       intitalStrainVoltage += ADCValue * Vcc / 1023.0;
       delay(10);
       }
       intitalStrainVoltage /= 6;
}

float measureTorque() {
         aftervolt = 0.0;         
          Vcc = readVcc()/1000.0;
          ADCValue = analogRead(strainPin);
       aftervolt = ADCValue * Vcc / 1023.0;
       torque = (aftervolt - intitalStrainVoltage) / 0.0088;
       return torque;
       

Not enough information.

Please post a link to the torque converter data sheet or user manual, and a wiring diagram (hand drawn is preferred, with all pins and connections clearly labeled).

Always post all the code. Snippets are rarely useful.

Sorry about that, here are the links to both the torque sensor and amplifier:

Amplifier: https://media.futek.com/content/futek/files/pdf/productdrawings/iaa200.pdf
Sensor: https://media.futek.com/content/futek/files/pdf/productdrawings/trd305.pdf

Here's a quick sketch and a Image:



// LCD Setup
#include <Wire.h>
#include <Adafruit_MCP23017.h>
#include <Adafruit_RGBLCDShield.h>
 
Adafruit_RGBLCDShield lcd = Adafruit_RGBLCDShield();

//Motor Controller Setup
#include <AccelStepper.h>
AccelStepper stepper(AccelStepper::DRIVER, 5, 3);

//SD Card
#include <SD.h>
const int chipSelect = 10;
File dataFile;
String dataString;

//RTC Setup
#include "RTClib.h"
RTC_DS1307 RTC;

//Pressure Transducer Setup
int pressurePin = A0;  
float pressure;
float diffPressure;
float pressureVoltage;


//Solenoid Setup
const int solenoid0 =  8;
const int solenoid1 =  9;
/*int solenoidPin = 7;*/

//Strain Gauge Setup
int strainPin = A1;
float intitalStrainVoltage;
float torque = 0.0;
float aftervolt;
// float torqueAvg = 40.0;
// float torqueTarget = 70.0;
float torqueTarget = 42.0;
int position = 1.75*2*5.5*2*200;
int new_position;
int bump_step;

//int cycles = 2000;
int count = 1;
unsigned int ADCValue;
float Vcc;   

//Reads a reference for analog signals
long readVcc() {

  long result;

  // Read 1.1V reference against AVcc
  ADMUX = _BV(REFS0) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1);
  delay(2); // Wait for Vref to settle
  
  ADCSRA |= _BV(ADSC); // Convert
  while (bit_is_set(ADCSRA,ADSC));
  result = ADCL;
  result |= ADCH<<8;
  result = 1154158L / result; // Back-calculate AVcc in mV
  return result;
}

void timestamp() {
       DateTime now = RTC.now();
       dataString += String(now.hour());
       dataString += String(':');
       dataString += String(now.minute());
       dataString += String(':');
       dataString += String(now.second());
       dataString += ",";
}

//Checks the current pressure
void readPressure() {
        pressure = 0;
        for (int i=0; i <= 99; i++) {         
          Vcc = readVcc()/1000.0;
          ADCValue = analogRead(pressurePin);
          pressureVoltage = (ADCValue / 1023.0) * Vcc;
          pressure += abs(7500 / 4 * (pressureVoltage - 1)); 
          delay(10);
       }
       pressure /= 100;
       /* Serial.print("Pressure:");
       Serial.println(pressure); */
       return;
}

void initialStrain() {
       intitalStrainVoltage = 0.0; 
       for (int i=0; i <= 5; i++) { 
       Vcc = readVcc()/1000.0;
       ADCValue = analogRead(strainPin);
       intitalStrainVoltage += ADCValue * Vcc / 1023.0;
       delay(10);
       }
       intitalStrainVoltage /= 6;
}

float measureTorque() {
         aftervolt = 0.0;         
          Vcc = readVcc()/1000.0;
          ADCValue = analogRead(strainPin);
       aftervolt = ADCValue * Vcc / 1023.0;
       torque = (aftervolt - intitalStrainVoltage) / 0.0088;
       return torque;
       

}

void setup() {
    Serial.begin (9600);  
  
    lcd.begin(16, 2);
    lcd.setBacklight(0x2);
    
    RTC.begin();

    if (! RTC.isrunning()) {
      /* Serial.println("RTC is NOT running!"); */
      // following line sets the RTC to the date & time this sketch was compiled
      RTC.adjust(DateTime(__DATE__, __TIME__));
    }    
    
    pinMode(solenoid0, OUTPUT);
    pinMode(solenoid1, OUTPUT);   
    pinMode(strainPin, INPUT);
    pinMode(7, OUTPUT);
    pinMode(10, INPUT);
    pinMode(12, INPUT);
    
    /* Serial.print("Initializing SD card..."); */
    pinMode(SS, OUTPUT);
  
   // see if the card is present and can be initialized:
   if (!SD.begin(chipSelect)) {
     /* Serial.println("Card failed, or not present"); */
     // don't do anything more:
     while (1) ;
   }
   /* Serial.println("card initialized."); */
  
   // Open up the file we're going to log to!
   dataFile = SD.open("datalog.csv", FILE_WRITE);
   if (! dataFile) {
     /* Serial.println("error opening datalog.txt"); */
     // Wait forever since we cant write data
     while (1) ;
   }
   
   //   stepper.setMaxSpeed(400);
   stepper.setAcceleration(5000);
}

void loop() {

lcd.clear();  
  
while(1) {
        
      lcd.setCursor(0, 0);
      lcd.print("Endurance Test");
      /* lcd.setCursor(0, 1);
      lcd.print(cycles);*/
      
      uint8_t buttons = lcd.readButtons();
      if (buttons & BUTTON_SELECT) {
          break;
      }
}
  
    lcd.clear();
    initialStrain();
    while(1) {
      lcd.setBacklight(0x2);
       
       dataString = "";
       
       lcd.setCursor(0, 0);
       lcd.print(count);
       
       dataString += String(count);
       dataString += ",";
       digitalWrite(7, LOW);
       
       timestamp();
       
       //Close Valve
       lcd.setCursor(0, 1);
       lcd.print("Close");
       
       // initialStrain();
       measureTorque();
       
       lcd.setCursor(11, 0);
       lcd.print("     ");
       lcd.setCursor(11, 0);
       lcd.print(torque,1);
       
       stepper.setMaxSpeed(2500);   
       stepper.runToNewPosition(-position);
       delay(500);
       measureTorque();
       
       //lcd.setCursor(11, 0);
       //lcd.print(stepper.currentPosition());
       
// we are shooting for between 114 - 126
      
      while (torque < torqueTarget)  {
          if (torqueTarget - torque > 0) { bump_step = -5; }
          if (torqueTarget - torque > 10) { bump_step = -10; }
          if (torqueTarget - torque > 20) { bump_step = -20; }
          stepper.move(bump_step);
          int position2 = stepper.currentPosition() + bump_step;
          while (stepper.currentPosition() != position2)
             stepper.run();
          delay(500);
          measureTorque();
          lcd.setCursor(11, 0);
          lcd.print(torque,1);
       }
       
       timestamp();
       lcd.setCursor(0, 1);
       lcd.print("PAUSE");
       
       position = abs(stepper.currentPosition());
       measureTorque();
       lcd.setCursor(11, 0);
       lcd.print(torque+20,1);
       
       if (torque > 60) {
       lcd.setCursor(0, 1);
       lcd.print("TORQUE ERROR");
       stepper.setMaxSpeed(500); 
       stepper.runToNewPosition(0); 
       while(1) {}  
       }

/*
         stepper.move(-4000);
         stepper.setMaxSpeed(20);  
         while (digitalRead(12) == LOW)
             stepper.run();
         stepper.stop();
         position = abs(stepper.currentPosition());
*/


/*
       for (int i = 0; measureTorque() < torqueTarget; i++)
       {
         bump_step = torqueTarget - torque;
         stepper.move(bump_step);
         int position2 = stepper.currentPosition() + bump_step;
           while (stepper.currentPosition() != position2)
             stepper.run();
           position += bump_step;
           Serial.println("bumped");
           Serial.print("Bump_steps: ");
           Serial.println(bump_step);
           if (bump_step = 0) { break; break;}
           delay(500);

       }
*/
       
       // measureTorque();
     //  lcd.setCursor(11, 0);
     //  lcd.print(torque,1);
       
       
       readPressure();
       lcd.setCursor(5, 0);
       lcd.print(pressure,0);
       delay(3500);
       
       //Vcc = readVcc()/1000.0;
       //ADCValue = analogRead(rhePin);
       //rheVoltage = ADCValue * Vcc / 1023.0;
       //rheValue = 30 * rheVoltage / 5 - 15;
       //lcd.setCursor(12, 1);
       //lcd.print(rheValue,1);
       
   
         
       /* Vcc = readVcc()/1000.0;
       int ADCValue1 = analogRead(strainPin);
       float aftervolt = ADCValue1 * Vcc / 1023.0;
       torque = (aftervolt - intitalStrainVoltage) / 0.0088; */
       
       // torqueAvg = (torqueAvg * count + torque) / (count + 1);       
       // torqueTarget = 200.0 + rheValue + (200.0 - torqueAvg);
             
       // torqueTarget = 62.0 + rheValue + (62 - torque);
       
       /*Serial.print("Torque Avg: ");+
       Serial.println(torqueAvg);
       Serial.print("Torque Target: ");
       Serial.println(torqueTarget);*/
       
       /* if (torque > 65.05 || torque < 58.86) {
         digitalWrite(7, HIGH);
       } */
       
       /* Serial.print("Torque: ");
       Serial.println(torque); */
       
       dataString += String(torque+20,2);
       dataString += ",";
       
       dataString += String(pressure,2);
       dataString += ",";   
       
       //Vent to Atmosphere
       lcd.setCursor(0, 1);
       lcd.print("Vent ");
       

       diffPressure = pressure;
       readPressure();
       diffPressure -= pressure;
       dataString += String(diffPressure,2);
       dataString += ","; 
       
       timestamp();
      
       digitalWrite(solenoid0, HIGH);
       delay(5000);           
       digitalWrite(solenoid0, LOW);
       digitalWrite(solenoid1, HIGH);
       delay(300);           
       digitalWrite(solenoid1, LOW);
       
       timestamp();
       delay(5000);
       //Read Pressure
       readPressure();
       lcd.setCursor(5, 0);
       lcd.print("     ");
       lcd.setCursor(5, 0);
       lcd.print(pressure,0);
       dataString += String(pressure/2);
       dataString += ",";   

       //Open Valve
       lcd.setCursor(0, 1);
       lcd.print("Open ");
       
       timestamp();

/*
       for(int i = 0; i = 19; i++) {
       stepper.move(-1);
          int position2 = stepper.currentPosition() - 1;
          while (stepper.currentPosition() != position2)
             stepper.run();
       delay (300);
       }
*/       
       stepper.setMaxSpeed(250); 
       stepper.runToNewPosition(-position + 1000);
       stepper.setMaxSpeed(2500); 
       stepper.runToNewPosition(0);
       if (torque > torqueTarget + 8)
         position= torque - torqueTarget;
             
       
       lcd.setCursor(0, 1);
       lcd.print("PAUSE");
       
       //count increase here
       /*if (digitalRead(10) == HIGH)
          position -= 10;
       if (digitalRead(12) == HIGH)
          position += 10;
       */
       timestamp();

       if (dataString.substring(1) == "V" || dataString.substring(1) == "c") {
          lcd.setCursor(0, 1);
          lcd.print("Error");
       }

       delay(6000);
       count++;
       
       dataString += "0";
        
       dataFile.println(dataString);
       /* Serial.println(dataString); */
       dataFile.flush();
     }  
      
}

I gather you did not write the code, and if that is the case, where did you find it?

The torque meter needs to be calibrated, or at least, the calibration has to be verified by comparison with a known good torque meter. What have you done along those lines?

The decimal value below is a calibration constant, where did it come from?

       torque = (aftervolt - intitalStrainVoltage) / 0.0088;

The long integer below is also a calibration constant, and is unique to every AVR-based Arduino. It corrects the error in the internal voltage reference and must be individually determined:

  result = 1154158L / result; // Back-calculate AVcc in mV

Finally, there are a number of settings on the torque sensor amplifier that need to be made correctly.

That is correct, I did not write the code. This is a project that I inherited so I'm not to familiar with it.

Yes. I recently had the old torque sensor calibrated and also purchased a brand new one. Both are calibrated and certified. A torque wrench and small torque meter were used to verify the torque. Both torque sensors matched and the wrench and small meter matched but the torque sensors did not match the wrench and small meter.

Not sure where that decimal value came from.. Could that be a uncertainty or a error constant?

Would you know where I could find more information on this constant?

The most important thing to do at this point is make sure that the program calculates the correct torque from the readings it obtains.

Take a step back and write a program that simply collects and reports ADC readings from the torque sensor amplifier, for some known values of torque. With that information forum members can help you update the program calibration constants.

See Adafruit's excellent guide on calibrating sensors: So, How Do We Calibrate? | Calibrating Sensors | Adafruit Learning System

Sound good, thanks for your help. What do you think about the program? Do you believe it can be cleaned up?

The program looks reasonable, but I advise to avoid using Strings on Arduino, especially AVR based ones with small memory, as they eventually cause program crashes due to poor memory management. Strings are a beginner's crutch and are not necessary.

torque = (aftervolt - intitalStrainVoltage) / 0.0088;

I'd start by removing that 'magic number' of 0.0088, and give it a meaningful name.

My suggestion would be to change that line to:

torque = (aftervolt - intitalStrainVoltage) * torqueCalibrationFactor;

where torqueCalibrationFactor = 1/0.0088 = 113.6

add a line before setup to declare torqueCalibrationFactor as a float:

float torqueCalibrationFactor = 113.6;

Then you need to come up with a new value for the torqueCalibrationFactor.

Start by multiplying that 113.6 by (48/68) to get 80.19, and use that as a starting figure, and then adjust it by trial and error until the LCD reading agrees with your calibrated meter.

That did it! Thanks for your help. The value ended up being 1/0.0042 = 236. As of yet, I'm unsure where the 0.0088 came from. When adding the,

float torqueCalibrationFactor = 236;

Would I add that above my strain gauge setup?

float torqueCalibrationFactor = 236;

//Strain Gauge Setup
int strainPin = A1;
float intitalStrainVoltage;
float torque = 0.0;
float aftervolt;
// float torqueAvg = 40.0;
// float torqueTarget = 70.0;
float torqueTarget = 62.0;
int position = 1.75*2*5.5*2*200;
int new_position;
int bump_step;

Yes, that would be a good place to put it.

Hopefully it will make updating the code easier if you do a routine calibration on the equipment.