Problem with stepper "following" a pulse input

Got a variable pulse input to an arduino and I want that to work exactly like the “motor knob example” in Arduino IDE. Differences between that example and my project is that I have the L297 as the controller. The stepper is going to be used in a speedometer.

The stepper is following the pulse input i’m feeding (between 0 and 800Hz) but it’s not running smooth. Doesnt jitter but it seems like its interrupted by something. If I go from 0 to 800Hz in a second its smooth all the way, but if I increase, say 15Hz/s it takes like 20 step waits about 300ms before it starts again.

Does anyone have any suggestion to make it smoother?

const int speedSensor = 4;
const int speedoDir = 14;
const int speedoStep = 5;

const int speedTeeth = 48;
float tireDiameter = 0.5; // Diameter of tire (meter)
float tireCircumference = PI * tireDiameter;

const int UpdateInterval = 500; // milliseconds
float LastUpdate = millis();
unsigned long speedPulseCount = 0l;
float currentSpeed = 0;
int prevSpeed = 0;
int pos = 0;
int val = 0;

void setup() {
  Serial.begin(9600);
  
  pinMode(speedSensor, INPUT);
  pinMode(speedoDir, OUTPUT);
  pinMode(speedoStep, OUTPUT);
  
  pinMode(odoDir, OUTPUT);
  pinMode(odoStep, OUTPUT);
  
  digitalWrite(speedoStep, HIGH);
  digitalWrite(speedoDir, LOW);
  
  attachInterrupt(0, speedCount, RISING);
  
}

void loop() {
  
  if ( millis() - LastUpdate >= UpdateInterval ) {
    
    // Calculate
    noInterrupts();
    // Number of rotations per sample (UpdateInterval)
    currentSpeed = speedPulseCount / (((millis() - LastUpdate) / 1000) * speedTeeth);
    // Speed in m/s
    currentSpeed = (currentSpeed * tireCircumference) / ((millis() - LastUpdate) / 1000);
    // m/s to km/h
    currentSpeed = currentSpeed * 3.6;
    interrupts();
    
    // Debug
    Serial.print("PulseCount:");
    Serial.print(speedPulseCount);
    Serial.print(" Current Speed:");
    Serial.print(currentSpeed, 0);
    Serial.print(" Val:");
    Serial.print(val);
    Serial.print(" Pos:");
    Serial.println(pos);
    
    // Reset pulse counter
    speedPulseCount = 0;
    LastUpdate = millis();
    prevSpeed = currentSpeed;
  }
  
  // "Follow" routine
  val = map((int)currentSpeed, 0, 220, 0, 200);
  
  if ( abs(val - pos) > 2 ) {
    if ( (val - pos) > 0 ) {
      digitalWrite(speedoDir, LOW);
      digitalWrite(speedoStep, LOW);
      delay(10);
      digitalWrite(speedoStep, HIGH);
      pos++;
    }
    
   if ( (val - pos) < 0 ) {
      digitalWrite(speedoDir, HIGH);
      digitalWrite(speedoStep, LOW);
      delay(10);
      digitalWrite(speedoStep, HIGH);
      pos--;
    }
  }
  
}

void speedCount() {
  speedPulseCount++;
}

Does anyone have any suggestion to make it smoother?

Lose the prints and the delay?

Wont that just stall the motor?

You're the one with the hardware; you tell me.

Replace the use of the delay() function with millis() - as you have used elsewhere.

...R

Thanks for helping me.

I tried removing the delays but the pulse train is at such a high frequency that the motor wont keep up.

I replaced delay() with millis() instead but it didn’t change anything.

I’m still getting pulse trains every 0.5 sec (which is the interrupt sample time), while it should be constant moving when I increase or decrease the pulse frequency.

Red trace: Pulses going into the arduino
Yellow trace: Pulses going to the stepper controller.

Current code:

const int speedoDir = 8;
const int speedoStep = 5;

const int speedTeeth = 48;
float tireDiameter = 0.5; // Diameter of tire (meter)
float tireCircumference = PI * tireDiameter;

const int tempSensor = A0;
const int tempVal = 0;
const int odoDir = 7;
const int odoStep = 6;

const int UpdateInterval = 500; // milliseconds
float lastUpdate = millis();
int stepUpdate = millis();
unsigned long speedPulseCount = 0l;
float currentSpeed = 0;
int prevSpeed = 0;
int pos = 0;
int val = 0;

void setup() {
  Serial.begin(9600);
  
  pinMode(speedoDir, OUTPUT);
  pinMode(speedoStep, OUTPUT);
  
  pinMode(odoDir, OUTPUT);
  pinMode(odoStep, OUTPUT);
  
  digitalWrite(speedoStep, HIGH);
  
  attachInterrupt(0, speedCount, RISING);
  
}

void loop() {
  
  if ( millis() - lastUpdate >= UpdateInterval ) {
    
    // Calculate
    noInterrupts();
    // Rotations per second
    currentSpeed = speedPulseCount / ( ( (millis() - lastUpdate) / 1000 ) * speedTeeth );
    // Speed in km/h
    currentSpeed = currentSpeed * tireCircumference * 3.6;
    interrupts();
    
    // Reset pulse counter
    speedPulseCount = 0;
    lastUpdate = millis();
    prevSpeed = currentSpeed;
  }
  
  // "Follow" routine
  currentSpeed = constrain( currentSpeed, 0, 220 );
  val = map( currentSpeed, 0, 220, 0, 400 );
  
  if ( millis() - stepUpdate >= 3 ) {
    stepUpdate = millis();   
    if ( abs(val - pos) > 2 ) {
      if ( (val - pos) > 0 ) {
        digitalWrite(speedoDir, LOW);
        digitalWrite(speedoStep, LOW);
        digitalWrite(speedoStep, HIGH);
        pos++;
      }
      
      if ( (val - pos) < 0 ) {
        digitalWrite(speedoDir, HIGH);
        digitalWrite(speedoStep, LOW);
        digitalWrite(speedoStep, HIGH);
        pos--;
      }
    }
  }  
}

void speedCount() {
  speedPulseCount++;
}

Try using delayMicroseconds(200) to set your step pulsewidth. Your pulse should go HIGH then LOW.
Your code has it going LOW then HIGH. That makes your ON time longer than your OFF time which is backwards.

Hmm, datasheet for L297 says:

Step clock. An active low pulse on this input advances the motor one increment. The step occurs on the rising edge of this signal.

Doesn't that mean it should go from high to low and back to high?

Anyway, I tried your suggestion without any changes to the "pause" issue.

adaptine:
I tried removing the delays but the pulse train is at such a high frequency that the motor wont keep up.

I did NOT mean that you dispense with the timing that was being provided by the delay() function - just that you generate that timing using millis().

See the second code example in this demo simple stepper program.

...R

Been quite bussy lately so havent had much time at getting this to work.

Gave it a try today and came up with this code:

// CONSTANTS
const int speedoDir = 8; // Pin speedostepper direction
const int speedoStep = 5; // Pin speedostepper step
const int stepsPerRev = 26 * 2; // Steps per rev times stepping factor

const int updateInterval = 25; // milliseconds
const int millisBetweenSteps = 25; // milliseconds
const int millisStepWidth = 3;

const int speedTeeth = 48; // Number of pulses per rotation
const int maxSpeed = 200; // Max cluster speed
const int tireDiameter = 500; // Diameter of tire (mm)
const float tireCircumference = PI * tireDiameter;

// VARIABLES
int pos = 0;
int val = 0;
float currentSpeed = 0;

unsigned long curMillis = 0;
unsigned long prevStepMillis = 0;
unsigned long prevStepWidthMillis = 0;
unsigned long lastUpdate = 0;
unsigned long lastUpdate2 = 0;
volatile int speedPulseCount = 0;
int speedPulseCount2 = 0;

void setup() {
  Serial.begin(9600);
  
  pinMode(speedoDir, OUTPUT);
  pinMode(speedoStep, OUTPUT);
  
  attachInterrupt(0, speedCount, FALLING);
  
}

void loop() {
  
  curMillis = millis();
  
  if ( (curMillis - lastUpdate) >= updateInterval ) {
    // Save variables
    noInterrupts();

    speedPulseCount2 = speedPulseCount;
    lastUpdate2 = lastUpdate;
    
    speedPulseCount = 0;
    lastUpdate += updateInterval;
    interrupts();  
    
    // Speed in m/s
    currentSpeed = (speedPulseCount2 * tireCircumference) / (speedTeeth * (curMillis - lastUpdate2));
    // Speed in km/h
    currentSpeed = (currentSpeed * 36) / 10;
    val = map( currentSpeed, 0, maxSpeed, 0, stepsPerRev );
    speedPulseCount = 0;
    
  }     
    
  // Speed difference bigger than 2?
  if ( abs(val - pos) > 2 ) {
    if ( (val - pos) > 0 ) {
      digitalWrite(speedoDir, LOW);
      speedStep();
      pos++;
    }
    
    if ( (val - pos) < 0 ) {
      digitalWrite(speedoDir, HIGH);
      speedStep();
      pos--;
    }
  } 
}

void speedStep() {
  if (curMillis - prevStepMillis >= millisBetweenSteps) {
    prevStepMillis += millisBetweenSteps;
    digitalWrite(speedoStep, HIGH);
    delay(millisStepWidth);
    digitalWrite(speedoStep, LOW);
  } 
}

void speedCount() {
  speedPulseCount++;
}

I’m using my frequency generator to sweep from 1Hz to 1.7kHz in 10 seconds before it start on 1Hz again. It seems to work somewhat ok, maybe a bit jittery. Video: Stepper sweep - YouTube

When it sweeps back to “zero” the off-time between pulses are only ~22µS while the on time is 3ms. However when it’s stepping forward the on-time is ~3ms while the off time can wary from ~22µS to as much as 300ms. Can someone explain this to me? Shouldnt “millisBetweenSteps” take care of the off-time between pulses? Seems non-existing while it should be 25ms?

Anyone got tips for improvements?