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++;
}
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.
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?