Lineer Actuator Control with Load Cell

Hi;

I try to control 24V DC motor lineer actuator with load cell. I use a MC33926 as motor driver (Pololu - MC33926 Motor Driver Carrier) and I use HX711 for control load cell. I use a S-type load cell. I will connect an actuator on one side of the load cell and an object on the other. The load cell will be located between the object and the actutor. System operation, when the button is pressed, the actuator will move forward and apply a force to the object. With the help of load cell, I can measure the applied force and when 3kg of force is applied to the object, the actuator will stop. After waiting a certain time, the actuator will move backwards and return to the starting point. I am sharing the code I wrote with you.

#include <HX711_ADC.h>

#define DOUT 8
#define SCK 9
#define button 10
#define motorIn1 5
#define motorIn2 6

HX711_ADC LoadCell(DOUT, SCK);
unsigned long t = 0;
float calibrationValue = -43618.36;
float weight = 0;
int buttonState = 0;
int _start = 0;

void setup()
{
  Serial.begin(57600);
  pinMode(motorIn1, OUTPUT);
  pinMode(motorIn2, OUTPUT);
  pinMode(button, INPUT);
  delay(10);
  Serial.println("Ölçüm Başlıyor...");
  LoadCell.begin();
  unsigned long stabilizingTime = 2000; //Stabilizasyon için mikrodenetleyiciye verilen zaman.
  boolean _tare = true; //Dara ile ilgili fonksiyon yazıldığı zaman bu satır true yapılır.
  LoadCell.start(stabilizingTime, _tare);
  LoadCell.setCalFactor(calibrationValue);
}
void Scale()
{
  static boolean newDataReady = 0;
  const int serialPrintInterval = 0; //Bu zaman değeri artırılarak seri ekrandaki değerlerin aktivitesi yavaşlatılabilir.
  if (LoadCell.update())
  {
    newDataReady = true;
  }
  if (newDataReady)
  {
    if (millis() > t + serialPrintInterval)
    {
      weight = LoadCell.getData();
      if (weight > -0.03 && weight <= 0.02)
      {
        weight = 0.00;
      }
      Serial.print("Ağırlık: ");
      Serial.print(weight);
      Serial.println("kg");
      newDataReady = 0;
      t = millis();
    }
  }
}

void Motor()
{
  
  analogWrite(motorIn1, 255);
  analogWrite(motorIn2, 50);

  if (weight >= 3.00)
  {
    Scale();
    analogWrite(motorIn1, 10);
    analogWrite(motorIn2, 10);
    
    
    if (weight < 3.00)
    {
      analogWrite(motorIn1, 255);
      analogWrite(motorIn2, 50);
    }
    delay(5000);
    analogWrite(motorIn1, 50);
    analogWrite(motorIn2, 255);
    _start = 0;
  }
}

void loop()
{
  buttonState = digitalRead(button);
  if (buttonState == 1)
  {
    _start++;
  }

  while (_start > 0)
  {
    Scale();
    Motor();
  }
}

The code works the way I want. But after applying 3kg of force, the load cell stops measuring. I want to get feedback from load cell constantly. I want to know that the force applied to the object is 3kg continuously. For example, if the applied force decreases, I will operate the actuator until 3 kg of force is applied again.

I wrote a code using another library. But there is the same problem with that. Load cell stops measuring after measuring 3kg. I am sharing the second code I wrote with you.

#include <HX711.h>

#define DOUT 8
#define CLK 9
#define button 10
#define motorIn1 5
#define motorIn2 6

HX711 scale;
float calibrationFactor = -43618.36; //Bu satıra kalibrasyondan sonra elde edilen kalbirasyon sabiti değeri yazılacaktır.
float weight;
int buttonState = 0;
int _start = 0;

void setup()
{
  Serial.begin(9600);
  pinMode(motorIn1, OUTPUT);
  pinMode(motorIn2, OUTPUT);
  pinMode(button, INPUT);
  scale.begin(DOUT, CLK);
  scale.set_scale();
  scale.tare();
  Serial.println("Ölçüme Başlamak için Butona Basın...");

}

void loop()
{

  buttonState = digitalRead(button);
  scale.set_scale(calibrationFactor);
  if (buttonState == 1)
  {
    _start++;
  }

  while (_start > 0)
  {
    analogWrite(motorIn1, 255);
    analogWrite(motorIn2, 50);


    weight = scale.get_units(10);
    if (weight > -0.01 && weight <= 0.05)
    {
      weight = 0.00;
    }

    Serial.print("Ağırlık:");
    Serial.print(weight, 2);
    Serial.print("kg");
    Serial.println();
    delay(100);


    if (weight >= 3.00)
    {
      scale.set_scale();
      scale.set_scale(calibrationFactor);
      weight = scale.get_units(10);
      Serial.print("Ağırlık:");
      Serial.print(weight, 2);
      Serial.println("kg");
      delay(100);
      analogWrite(motorIn1, 10);
      analogWrite(motorIn2, 10);
      delay(5000);
      analogWrite(motorIn1, 50);
      analogWrite(motorIn2, 255);
      _start = 0;
      /*
        if(weight!=oldWeight)   //Sadece ağırlık değiştiğinde Serial port ekranına değer yazma komutu...
        {
          oldWeight=weight;
          Serial.print("Ağırlık:");
          Serial.print(weight,2);
          Serial.print("kg");
          Serial.println();
        }*/
    }

  }
}

The Load Cell’s Datasheet I use: https://kobastar.com/wp-content/uploads/2020/05/STS-EN.pdf

The Lineer Actuator’s Datasheet I use: https://www.mepateknik.com/wp-content/uploads/lineer_aktuator_TA2_dokuman.pdf

I made the connections of the motor driver by getting help from the site on the link. (Dual MC33926 motor driver - control pins - General Discussions - RobotShop Community)

Put some Serial.prints in there so you can see where the execution goes.

I find your code rather confusing, but given that the issue occurs relating to 3kG and that number appears repeatedly in your code, it seems likely that you have a bug rather than a problem with the load cell.

Tomorrow, I will try your recommend. Could using a timer interrupt be a solution? So if I check if only 3kg is applied at certain intervals. Would such a solution with Interrupt be feasible?

Hi;

I’m still trying to find a solution. I made some changes in the code. But still same problem continues to occur.

#include <HX711_ADC.h>

#define DOUT 8
#define SCK 9
#define button 10
#define motorIn1 5
#define motorIn2 6

HX711_ADC LoadCell(DOUT, SCK);
unsigned long t = 0;
float calibrationValue = -43618.36;
float weight = 0;
int buttonState = 0;
int _start = 0;

void setup()
{
  Serial.begin(57600);
  pinMode(motorIn1, OUTPUT);
  pinMode(motorIn2, OUTPUT);
  pinMode(button, INPUT);
  delay(10);
  Serial.println("Ölçüm Başlıyor...");
  LoadCell.begin();
  unsigned long stabilizingTime = 2000; //Stabilizasyon için mikrodenetleyiciye verilen zaman.
  boolean _tare = true; //Dara ile ilgili fonksiyon yazıldığı zaman bu satır true yapılır.
  LoadCell.start(stabilizingTime, _tare);
  LoadCell.setCalFactor(calibrationValue);
}

void loop()
{

  Scale();
  buttonState = digitalRead(button);
  if (buttonState == 1)
  {
    _start = 1;
  }

  while (_start == 1)
  {
    Scale();
    Motor();
    
  }
  while (_start == 2)
  {
    Scale();
    Control();
    
  }
  while (_start == 3)
  {
    Motor_Rev();
    
  }
}

void Scale()
{
  static boolean newDataReady = 0;
  const int serialPrintInterval = 0; //Bu zaman değeri artırılarak seri ekrandaki değerlerin aktivitesi yavaşlatılabilir.
  if (LoadCell.update())
  {
    newDataReady = true;
  }
  if (newDataReady)
  {
    if (millis() > t + serialPrintInterval)
    {
      weight = LoadCell.getData();
      if (weight > -0.03 && weight <= 0.02)
      {
        weight = 0.00;
      }
      Serial.print("Ağırlık: ");
      Serial.print(weight);
      Serial.println("kg");
      newDataReady = 0;
      t = millis();
    }
  }
}

void Motor()
{
  
  analogWrite(motorIn1, 255);
  analogWrite(motorIn2, 50);

  if (weight >= 3.00)
  {
    Scale();
    Serial.print("Ağırlık: ");
    Serial.print(weight);
    Serial.println("kg");
    analogWrite(motorIn1, 10);
    analogWrite(motorIn2, 10);
    delay(2000);
    _start = 2;
  }
}

void Control()
{

  delay(1000);
  if (weight < 3.00 && weight >= 2.00)
  {
    Scale();
    Serial.print("Ağırlık: ");
    Serial.print(weight);
    Serial.println("kg");
    analogWrite(motorIn1, 255);
    analogWrite(motorIn2, 50);
  }
  else
  {
    delay(3000);
    _start=3;
  }
}

void Motor_Rev()
{
  analogWrite(motorIn1, 50);
  analogWrite(motorIn2, 255);
  delay(5000);
  _start=0;
}

When _start variable is 1, loadcell continues to measure. But when _start variable becomes 2 or 3, loadcell stops measuring. No data is coming into the serial port screen. I would be very happy if you could help with the subject.

Just because it isn't sending serial data doesn't have to mean it's not measuring. You could still add more debugging prints to see where execution goes.

It seems overly complex to me though. I'd just read the scale on every iteration of loop if the weight has changed. Then have a little state machine that extends, sustains or retracts as needed.

The code dealing with the scale isn't anything to do with the motor, so simply call Scale() every time
through loop() so the scale is always being read.

Then the business logic for dealing with the motor only has to check the current weight
reading when it needs to make a decision.

Separation of concerns is a very important mantra for programming - keeps things separately
coded unless there's an overriding reason to mix them up - and even then don't do it without
careful thought.

Hello Everyone;

I solved the problem I mentioned above by removing the delay() command. I used another circuit as a stopwatch. When I make a stopwatch using the delay() command with Arduino, the load cell stops measuring and even after the time given in the delay() command is completed, it doesn’t start to measure. Do you have any idea what could be the reason for the load cell library not workig properly with delay() command?

Below, I am sharing the link of the library I use and the current code.

#include <LiquidCrystal_I2C.h>
#include <Wire.h>
#include <HX711_ADC.h>

#define motorIn1 10
#define motorIn2 11
#define DOUT 9
#define SCK 8
#define button_1 4
#define button_2 5
#define button_3 6
#define greenLed 13
#define blueLed A0

HX711_ADC LoadCell (DOUT, SCK);
LiquidCrystal_I2C lcd(0x27, 16, 2);
unsigned long t = 0;
float calibrationValue = -43618.36;
float weight = 0.0;
int buttonState_1 = 0;
int buttonState_2 = 0;
int buttonState_3 = 0;
int _start = 0;

void setup()
{
  lcd.begin();
  lcd.setCursor(1, 0);
  lcd.print("E.C.A. Valfsel");
  lcd.setCursor(0, 1);
  lcd.print("Kuvvet:");
  lcd.setCursor(7, 1);
  lcd.print(weight);
  Serial.begin(57600);
  pinMode(button_1, INPUT);
  pinMode(button_2, INPUT);
  pinMode(button_3, INPUT);
  pinMode(motorIn1, OUTPUT);
  pinMode(motorIn2, OUTPUT);
  pinMode(greenLed, OUTPUT);
  pinMode(blueLed, OUTPUT);
  delay(10);
  Serial.println("Ölçüm Başlıyor...");
  LoadCell.begin();
  unsigned long stabilizingTime = 2000;
  boolean _tare = true;
  LoadCell.start(stabilizingTime, _tare);
  LoadCell.setCalFactor(calibrationValue);
  attachInterrupt(0, Motor_Rev, RISING);
  digitalWrite(greenLed, LOW);
  digitalWrite(blueLed, LOW);
}

void loop()
{
  buttonState_1 = digitalRead(button_1);
  buttonState_2 = digitalRead(button_2);
  buttonState_3 = digitalRead(button_3);
  if (buttonState_1 == 1)
  {
    _start = 1;
  }
  if (buttonState_2 == 1)
  {
    _start = 2;
  }
  if (buttonState_3 == 1)
  {
    _start = 3;
  }
  while (_start == 1)
  {
    Scale();
    Test1();
  }
  while (_start == 2)
  {
    Scale();
    Test2();
  }
  while (_start == 3)
  {
    Scale();
    Test3();
  }
}

void Scale()
{
  static boolean newDataReady = 0;
  const int serialPrintInterval = 0;
  if (LoadCell.update())
  {
    newDataReady = true;
  }
  if (newDataReady)
  {
    if (millis() > t + serialPrintInterval)
    {
      weight = LoadCell.getData();
      if (weight > -0.03 && weight <= 0.02)
      {
        weight = 0.00;
      }
      Serial.print("Ağırlık: ");
      Serial.print(weight);
      Serial.println("kg");
      lcd.setCursor(7, 1);
      lcd.print(weight);
      newDataReady = 0;
      t = millis();
    }
  }
}

void Test1()
{
  digitalWrite(greenLed, HIGH);
  digitalWrite(blueLed, LOW);
  if (weight < 3.00 && weight >= 0.00)
  {
    analogWrite(motorIn1, 50);
    analogWrite(motorIn2, 255);
  }
  else if (weight >= 3.00)
  {
    Scale();
    analogWrite(motorIn1, 10);
    analogWrite(motorIn2, 10);
  }
  else if (weight < 3.00 && weight >= 1.00)
  {
    Scale();
    analogWrite(motorIn1, 50);
    analogWrite(motorIn2, 255);
  }
}

void Test2()
{
  digitalWrite(greenLed, HIGH);
  digitalWrite(blueLed, LOW);
  if (weight < 5.00 && weight >= 0.00)
  {
    analogWrite(motorIn1, 143);
    analogWrite(motorIn2, 255);
  }
  else if (weight >= 5.00)
  {
    Scale();
    analogWrite(motorIn1, 10);
    analogWrite(motorIn2, 10);
  }
  else if (weight < 5.00 && weight >= 3.00)
  {
    Scale();
    analogWrite(motorIn1, 143);
    analogWrite(motorIn2, 255);
  }
}

void Test3()
{
  digitalWrite(greenLed, HIGH);
  digitalWrite(blueLed, LOW);
  if (weight < 10.00 && weight >= 0.00)
  {
    analogWrite(motorIn1, 143);
    analogWrite(motorIn2, 255);
  }
  else if (weight >= 10.00)
  {
    Scale();
    analogWrite(motorIn1, 10);
    analogWrite(motorIn2, 10);
  }
  else if (weight < 10.00 && weight >= 7.00)
  {
    Scale();
    analogWrite(motorIn1, 143);
    analogWrite(motorIn2, 255);
  }
}
void Motor_Rev()
{
  digitalWrite(greenLed, LOW);
  digitalWrite(blueLed, HIGH);
  analogWrite(motorIn1, 10);
  analogWrite(motorIn2, 10);
  delay(100);
  analogWrite(motorIn1, 255);
  analogWrite(motorIn2, 50);
  delay(10000);
  _start = 0;
}

Load cell stops measuring only when interrupth is active in this code. Because there is only delay() command inside the Motor_Rev() function.

This topic was automatically closed 120 days after the last reply. New replies are no longer allowed.