Help on a linear actuator project with hall sensor

I am hoping somebody can help me I am trying to program and control a linear actuator with hall effect sensor. Firstly I really have tried to do this by myself by following a tutorial and a YouTube post from Firgelli Automation but its not working.

Here is the tutorial: https://www.firgelliauto.com/blogs/tutorials/feedback-from-a-hall-effect-sensor

Here is the You Tube video: Video

Components:

  1. UNO R3
  2. Actuator model: Zoom Industrial Z0600WH, 5 wires red and black for power, yellow wire says its the sensor wire, the green wire is the ground and the white wire 5V for sensor.
  3. BTS 7690 Motor controller board

I have drawn up the schematic of the hardware and attached it.

The code is meant to first home the actuator, when I activate the Uno the actuator just jogs briefly.

The two buttons are then meant to control the extension and the retraction of the actuator, both buttons for some reason extend the actuator? Also the serial output shows a value of 1.4 when its used the other outputs 0.0?

At this point I don't know if the code is wrong or I have some wiring wrong? The guy on the video does not really explain some of the connections but I think I copied them correctly.

Hope somebody can help point me in the right direction. Thanks

/*Hall effect linear actuator code with feedback, full code
*/ 

long pos = 0;                     // Actuator Position
long prevPos = 1;                 // Previous Position, starts !=pos 
long steps = 0;                   // Pulses from Hall effect sensors
long prevsteps = 0;               // Previous steps counted
float conNum = 0.0000286;         // Convert to inches
bool dir = 0;                     // Direction of actuator (0= retract, 1=Extend)   
int Speed = 0;                    // Speed Variable
bool homeFlag = 0;                // Flag use to know if the actuator is home
unsigned long prevTimer = 0;      // Previous Time Stamp
unsigned long lastStepTime = 0;   // Time stamp of last pulse
int trigDelay = 500;              // Delay between pulse in microseconds


void setup() {
  pinMode(10, OUTPUT);            // Configure pin 10 as an output
  pinMode(11, OUTPUT);            // Configure pin 11 as an output
  pinMode(8, INPUT_PULLUP);       // Input for Button
  pinMode(9, INPUT_PULLUP);       // Input for Button

  /* Setting Up Interrupt*/
  pinMode(2, INPUT);
  attachInterrupt(digitalPinToInterrupt(2), countSteps, RISING);

  Serial.begin(9600);
}

void loop() {

  /*Homing the Linear Actuator*/
  if(homeFlag == 0){homeActuator();}

  /*Run Linear Actuator*/
  if(digitalRead(8) == HIGH & digitalRead(9) == LOW){
    // Retract Actuator
    dir = 0;
    Speed = 255;
    analogWrite(10, 0);
    analogWrite(11, Speed);
    if(millis() - prevTimer > 100){                          //Update the position Every 1/10 second
    updatePosition();
    prevTimer = millis();
    if(pos == prevPos | pos == 0){ pos = 0;}                  // Corrects Position
    else {prevPos = pos;}
    Serial.println(convertToInches(pos));
    }
  }
    else if(digitalRead(8) == LOW & digitalRead(9) == HIGH){
      //Extend Actuator
      dir = 1;
    Speed = 255;
    analogWrite(10, 0);
    analogWrite(11, Speed);
    if(millis() - prevTimer > 100){                          //Update the position Every 1/10 second
    updatePosition();
    prevTimer = millis();
    if(pos == prevPos | pos == 49000){ pos = 49000;}                  // Corrects Position
    else {prevPos = pos;}
    Serial.println(convertToInches(pos));
    }
  }
    else{
    // Stop Actuator
    Speed = 0;
    analogWrite(10, 0);
    analogWrite(11, 0);
  }
}

/*InterruptService Routine*/
void countSteps(void) {
  if(micros()-lastStepTime > trigDelay){
    steps++;
    lastStepTime = micros();
  }
}

/*Homing Function*/
void homeActuator(void){
  prevTimer = millis();
  while(homeFlag == 0){
    Speed = 255;
    analogWrite(10, 0);
    analogWrite(11, Speed);
    if(prevsteps == steps){
     if(millis() - prevTimer > 100){
        analogWrite(10, 0);
        analogWrite(11, 0);
        steps = 0;
        Speed = 0;
        homeFlag = 1;
      }
    }else{
      prevsteps = steps;
      prevTimer = millis();
    }
  }
}

/*Update Position Function*/
void updatePosition(void){
  if(dir == 1){
    pos = pos + steps;
    steps = 0;
  } else {
    pos = pos - steps;
    steps = 0;
  }
}

/*Convert To Inches Function*/
float convertToInches(long pos){
  return conNum*pos;
}
 

  • What voltage level goes to Pin #2 ?
  • Does Pin #2 have a pullup in the actuator ?

  • Do you want:
bool dir = 0; 
. . .
 if(digitalRead(8) == HIGH & digitalRead(9) == LOW)
. . . 
 if(pos == prevPos | pos == 0)

Or

bool dir = false; 
. . . 
 if(digitalRead(8) == HIGH && digitalRead(9) == LOW)
. . .
 if(pos == prevPos || pos == 0)

Please post a hand drawn wiring diagram, with all connections and pins clearly labeled. Fritzing diagrams are difficult to interpret, not very useful, and not appreciated on this forum.

There are several problems with the code. The interrupt routine should just count pulses (incrementing or decrementing depending on direction of travel).

All variables shared between interrupt routines and the main program must be declared volatile, and protected from corruption as follows.

// global variable
volatile int steps = 0;

/*InterruptService Routine*/
void countSteps(void) {
    steps++;  //or steps-- if traveling in the negative direction
  }

// in loop():
...
noInterrupts();
int steps_copy = steps;  //make copy with interrupts off
interrupts();
Serial.println(steps_copy);

To get started, just wire up the linear actuator, motor driver and motor power supply, and verify that you can make the actuator travel between the end switches.

Then connect the Hall effect sensor and make sure you can read pulses.

Thanks for the reply. I don’t know the answer to that. The sensor is powered by the 5V rail on the breadboard?

I did see some documentation that said add a 10K resistor to that yellow wire to read pulses? Is the important?

Apparently pin 2 is for an Interrupt?

A pullup resistor is required. You are getting way ahead of yourself by trying to implement someone else's complicated program intended for another actuator.

  • Yes.

BTW

  • For readability, please format your code like the below.

Instead of this style,

if(millis() - prevTimer > 100){                        
updatePosition();
prevTimer = millis();
if(pos == prevPos | pos == 0){ pos = 0;}                 
else {prevPos = pos;}
Serial.println(convertToInches(pos));
}

Do this instead:

if (millis() - prevTimer > 100)                         
{
  updatePosition();
  prevTimer = millis();

  if (pos == prevPos | pos == 0)
  {
    pos = 0; 
  }

  else
  {
    prevPos = pos;
  }

  Serial.println(convertToInches(pos));
}

I will draw up a diagram. Maybe I could ask for some basic guidance with what I would like to do as you think I am getting ahead of myself, we all have to start somewhere right?

Ideally I want an actuator to fully retract and then via buttons drive it to 5 specific positions?

I would rehome the actuator each time before extending it to a new position. I thought if I can find a low speed and run it for a specific time I could get 5% tolerance for the given position?

I understood the Hall effect approach would improve accuracy, is that not true?

If the 5% is achievable by simply using PWM with an actuator without feedback then I will go that way.

Thanks

Given at the end of post #3 above.

I understood the Hall effect approach would improve accuracy, is that not true?

The Hall effect sensor allows you to measure the extension of the arm quite accurately, once you learn how to count pulses, taking direction of travel into account.

  • Is the output of your Hall Effect sensor analog or digital ?

Link to actuator product page, with built in Hall effect sensor.

will do, will auto format fodo that in the editor? Once again thanks for the help.

Sorry another no idea, the datasheet is very rudimentary. Any way i can check it with a multimeter?

yep i have that, did something jump out to you that i missed?

  • You might be able to look at the output voltage to see what its maximum and minimum are.

Firstly thanks for the help to both of you..
OK so I simplified things, swapped the actuator for one without feedback and have the buttons working properly, it retracts and extends when I hold the buttons down at the speed I set, so that's good.

So maybe this simple version will do what I want if I can simply press a button and it drives for an amount of time? But I assume that's a different type of button? Or will pressing the button once allow me to set the speed and time if I dont hold it down?

Here is the code I cobbled together which works, hopefully formatted correctly:

byte Speed = 0; // Intialize Varaible for the speed of the motor (0-255);
int RPWM = 10;  //connect Arduino pin 10 to IBT-2 pin RPWM
int LPWM = 11;  //connect Arduino pin 11 to IBT-2 pin LPWM

void setup()
{
pinMode(10, OUTPUT); // Configure pin 10 as an Output
pinMode(11, OUTPUT); // Configure pin 11 as an Output
pinMode(2, INPUT_PULLUP);  //Input for Button
pinMode(3, INPUT_PULLUP);  //Input for Button

}

void loop()
{
  if(digitalRead(2) == HIGH & digitalRead(3) == LOW)
 {  //Retract Actuator at Speed 100
  Speed = 100;
  analogWrite(10, 0);
  analogWrite(11, Speed);
 }
   else if(digitalRead(2) == LOW & digitalRead(3) ==HIGH)
 {  //Extened Actuator at Speed 100
   Speed = 100;
   analogWrite(10, Speed);
   analogWrite(11, 0);
 }
else{
    // Stop Actuator
   analogWrite(10,0);
   analogWrite(11, 0);
}
}

  if(digitalRead(2) == HIGH & digitalRead(3) == LOW)
 {  //Retract Actuator at Speed 100
  Speed = 100;
  analogWrite(10, 0);
  analogWrite(11,
 
  • Use &&

  • Do you know how to write code for a switch to react as push ON push OFF ?

& is bitwise AND and is not appropriate here.
&& is logical AND

If you don't know about operator precedence you can easily get into trouble. Make your intent obvious by using parentheses as follows.

  if( (digitalRead(2) == HIGH) && (digitalRead(3) == LOW) )

One possibility for using buttons to move the actuator is a while loop:

  while (digitalRead(2) == LOW )  //if button 2 is pressed, retract actuator
 {  //Retract Actuator at Speed 100
  Speed = 100;
  analogWrite(10, 0);
  analogWrite(11, Speed);
 }

I will look in to learning the first point. On the second point. Surely “while” means when the button continues to be pressed?

I would like an input method that executes code that drives the actuator at a given speed for a given time then stops?

Thanks

For that, you need to learn how to detect state change, that is when the button becomes pressed, or is released, rather than "pressed" or "not pressed".

Take a look at the Arduino example program File>Examples>02.Digital>StateChangeDetection

For timing code, take a look at the Blink Without Delay example.

  • Try this sketch version.

  • Note: switches are wired from the pin to GND.

  • If you understand what is being done, how would you need it changed ?

  • Questions ?

//================================================^================================================
//
//  https://forum.arduino.cc/t/help-on-a-linear-actuator-project-with-hall-sensor/1292838
//
//
//
//  Version    YY/MM/DD    Comments
//  =======    ========    ========================================================================
//  1.00       YY/MM/DD    Running code
//

//================================================
#define LEDon              HIGH   //PIN---[220R]---A[LED]K---GND
#define LEDoff             LOW

#define PRESSED            LOW    //+5V---[Internal 50k]---PIN---[Switch]---GND
#define RELEASED           HIGH

#define CLOSED             LOW    //+5V---[Internal 50k]---PIN---[Switch]---GND
#define OPENED             HIGH

#define ENABLED            true
#define DISABLED           false

const byte  mySwitch1    = 2;   //+5V---[Internal 50k]---PIN---[Switch]---GND   Push = LOW
const byte  mySwitch2    = 3;   //+5V---[Internal 50k]---PIN---[Switch]---GND   Push = LOW

const byte  RPWM         = 10;  //connect Arduino pin 10 to IBT-2 pin RPWM
const byte  LPWM         = 11;  //connect Arduino pin 11 to IBT-2 pin LPWM

const byte heartbeatLED  = 13;  //Optional, toggles every 500ms

byte Speed;                     // Intialize Varaible for the speed of the motor (0-255);
byte mySwitch1LastState;
byte mySwitch2LastState;

//timing stuff
unsigned long heartbeatTime;
unsigned long switchesTime;

//                                           s e t u p ( )
//================================================^================================================
void setup()
{
  Serial.begin(115200);

  pinMode(10, OUTPUT);
  pinMode(11, OUTPUT);
  pinMode(heartbeatLED, OUTPUT);
  
  pinMode(mySwitch1, INPUT_PULLUP);
  pinMode(mySwitch2, INPUT_PULLUP);

} //END of   setup()

//                                            l o o p ( )
//================================================^================================================
void loop()
{
  //========================================================================  T I M E R  heartbeatLED
  //is it time to toggle the heartbeat LED ?
  if (millis() - heartbeatTime >= 500ul)
  {
    //restart this TIMER
    heartbeatTime = millis();

    //toggle the heartbeat LED
    digitalWrite(heartbeatLED, digitalRead(heartbeatLED) == HIGH ? LOW : HIGH);
  }

  //========================================================================  T I M E R  checkSwitches
  //is it time to check our switches ?
  if (millis() - switchesTime >= 50ul)
  {
    //restart this TIMER
    switchesTime = millis();

    checkSwitches();
  }


  //================================================
  // other non blocking code goes here
  //================================================


} //END of   loop()


//                                   c h e c k S w i t c h e s ( )
//================================================^================================================
void checkSwitches()
{
  byte pinState;

  //========================================================================  mySwitch1
  pinState = digitalRead(mySwitch1);

  //===================================
  //has this switch changed state ?
  if (mySwitch1LastState != pinState)
  {
    //update to this new state
    mySwitch1LastState = pinState;

    //========================
    //did this switch go closed ?
    if (pinState == CLOSED)
    {
    }

    //========================
    //did this switch go opened ?
    else if (pinState == OPENED)
    {
    }

  } //END of   mySwitch1.pin


  //========================================================================  mySwitch2
  pinState = digitalRead(mySwitch2);

  //===================================
  //has this switch changed state ?
  if (mySwitch2LastState != pinState)
  {
    //update to this new state
    mySwitch2LastState = pinState;

    //========================
    //did this switch go closed ?
    if (pinState == CLOSED)
    {
    }

    //========================
    //did this switch go opened ?
    else if (pinState == OPENED)
    {
    }

  } //END of   mySwitch2.pin


  //========================================================================
  if (mySwitch1LastState == RELEASED && mySwitch2LastState == PRESSED)
  {
    //Retract Actuator at Speed 100
    Speed = 100;
    analogWrite(10, 0);
    analogWrite(11, Speed);
  }

  else if (mySwitch1LastState == PRESSED && mySwitch2LastState == RELEASED)
  {
    //Extened Actuator at Speed 100
    Speed = 100;
    analogWrite(10, Speed);
    analogWrite(11, 0);
  }

  else
  {
    //Stop Actuator
    analogWrite(10, 0);
    analogWrite(11, 0);
  }

} //END of   checkSwitches()


//================================================^================================================