Problem with nema 17 and potentiometer

Hello,

I have a project with a Nema 17 motor, which moves a carriage through a pulley and a GT2 belt, same mechanism as a 3D printer, to controll the position of the Nema I'm using a linear potentiometer.

  1. This linear potentiometer is not linear, I'm using a ground wiped configuration which gives me a semi-linear configuration, basically both ends of the pot aren't linear, that's why I only use the middle section, which is physically restricted, I also use a 100n capacitor between the analog input and GND to smooth the output.

  2. My hardware is based on an arduino nano with a TMC2209 driver in STEP/DIR mode with 8 microsteps, pretty generic. (The schematic is working properlly, that's why im not posting it)

My code works, the stepper follows the potentiometer position with a rather fast movement, the problem is that it vibrates a lot, I can feel the pass of each step if I touch the carriage where the motor is attached, the movement isn't smooth at all, I think it has something to do with my code.

Do you have any suggestions on how should I change it?

#define stepPin 6
#define dirPin 3

#define POT A6

int pot;
int prev;
int delta;

int maxim;

int sensorValue = 0;         // the sensor value
int sensorMin = 250;        // minimum sensor value
int sensorMax = 800;           // maximum sensor value

void setup()
{
  // Sets the two pins as Outputs
  pinMode(stepPin, OUTPUT);
  pinMode(dirPin, OUTPUT);

  Serial.begin (9600);
 delay (1000);
}
void loop()
{
  pot = analogRead (POT);

  pot = constrain(pot, sensorMin, sensorMax);
  pot = map(pot, sensorMin, sensorMax, 0, 1000);

  pot = pot / 4 * 4;

  delta = pot - prev;

  prev = pot;
    
  Serial.println (pot);
  Serial.print ("ACTUAL: ");

  if (abs(delta) > 1)
  {
    //Serial.println ("VARIACION");  
    if (delta >= 0)
    {
      digitalWrite(dirPin, HIGH);
      for (int x = 0; x < abs(delta); x++)
      {
        digitalWrite(stepPin, HIGH);
        delayMicroseconds(150);
        digitalWrite(stepPin, LOW);
        delayMicroseconds(150);
      }
    }
    else if (delta <= 0)
    {
      digitalWrite(dirPin, LOW);
      for (int x = 0; x < abs(delta); x++)
      {
        digitalWrite(stepPin, HIGH);
        delayMicroseconds(150);
        digitalWrite(stepPin, LOW);
        delayMicroseconds(150);
      }
    }

  }
}

What is this: "pot = pot / 4 * 4;" ?

The 100nF capacitor is good, but you can also calculate the average of a few samples, and then add a filter in software. If you have a filter in software, then you can easily change how strong the filter should be.

The AccelStepper library can set a acceleration, that prevents short vibration.

Could you try to split the input from the output ?
Can you print the value of delta to the serial monitor to check how steady it is ?
Can you control the stepper motor with code, to see if you can make them move smooth with code ?

On this forum, when someone does not want to show something, then we say: the problem is in the part that you are not showing :face_with_raised_eyebrow: Can you show the schematic ? Just for some peace of mind for us :dove:

[UPDATE]
I see now that you show the potentiometer value to the Serial Monitor. That is very coarse. The line "pot = pot / 4 * 4;" makes it worse. There is no dampening at all.

Your sketch:

You get what you pay for! Check major electronic distributors for actual linear potentiometers.

This is my example for a smooth working of the stepper motor.
Open the "Serial Plotter" instead of the "Serial Monitor" to see the graphs for the potentiometer value before and after filtering.

// For: https://forum.arduino.cc/t/problem-with-nema-17-and-potentiometer/1031505
//
// Formatted the text a little.
// Changed pins to "const int", changed small other things.
// Added AccelStepper library.
// Added a 50Hz millis-timer to sample and average the sensor data.
// Added a low-pass filter.
// Show potentiometer value before and after filtering.
//

#include <AccelStepper.h>

const int stepPin = 6;
const int dirPin = 3;
const int potPin = A6;

AccelStepper stepper(AccelStepper::DRIVER, stepPin, dirPin);

const int sensorMin = 250;         // minimum sensor value
const int sensorMax = 800;         // maximum sensor value

float sensorValue;                 // a global variable for the filtered value

unsigned long previousMillis;
const unsigned long interval = 20; // for 50Hz sample rate

void setup()
{
  Serial.begin(115200);

  stepper.setMaxSpeed(500);
  stepper.setAcceleration(40);

  // Set the sensorValue to a initial value.
  // To make the filter start with a real value.
  sensorValue = getSensor(potPin);
}

void loop()
{
  unsigned long currentMillis = millis();

  // Sample the input with 50Hz.
  // That seems enough and a fixed timing is needed for the filter.
  if( currentMillis - previousMillis >= interval)
  {
    previousMillis = currentMillis;

    float newSensorValue = getSensor(potPin);
    Serial.print(newSensorValue);
    Serial.print(",");

    // Low-pass filter, for example with 5%.
    sensorValue = 0.95 * sensorValue + 0.05 * newSensorValue;
    Serial.print(sensorValue);
    Serial.println();

    // To do: Create a dead area.

    stepper.moveTo( (long) sensorValue);
  }

  stepper.run();        // this function makes the stepper motors move
}

// This function gets the sensor data.
// It returns 0...1000 as a floating point.
// Only a part of the potentiometer is used.
float getSensor(int pin)
{
  // Take 10 samples and calculate the average.
  // The result should be 0...1000.
  // Using floating point helps for the low-pas filter.
  long total = 0;
  for( int i=0; i<10; i++)
  {
    int pot = analogRead(pin);
    pot = constrain(pot, sensorMin, sensorMax);
    pot = map(pot, sensorMin, sensorMax, 0, 1000);
    total += pot;               // calculate the total of the samples
  }
  return(float(total) / 10.0);  // the average as a floating point
}

Try the sketch in Wokwi:

Thank you so much for this code, I think the key here was the AccelStepper library with it's movetoposition function, it now moves really smoothly and the filter for the potentiometer works absolutely perfect, thank you again for the code, it was really helpfull, I will use the same filter for lots of projects from now on.

The potentiometer has a low-pass filter for the input data.
The output data has a acceleration limit for the stepper motor.
Together they make everything smooth and slow.

This is a 5% filter:

sensorValue = 0.95 * sensorValue + 0.05 * newSensorValue;  // 5% low-pass filter

It will be slower with a lower value and faster with a higher value. For example a 50% low-pass filter is faster:

sensorValue = 0.50 * sensorValue + 0.50 * newSensorValue;   // 50% low-pass filter

You can remove the low-pass filter if you don't need it. Perhaps a limit for the acceleration is enough.

The sample rate has also influence. The 20ms interval can be make longer (slower) or shorter (faster). I would keep the 20ms.

Taking 10 samples for the average is very fast. There is no need to shorten that.

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