 # Speed loop execution time

I am running a voltage sensor and stepper motor. The motor moves a piece and I get a read from the voltage sensor. The code needs to accomplish 2 things:

1. get a voltage from a sensor

2. run a stepper motor at desired speed (using the `millisBetweenSteps` variable) for n number of cycles (using `maxSteps`).

I am using microstepping to smooth the motor vibrations.

The code that I have accomplishes the task. However, the time between loop iterations is around 3 ms (see `Serial.println(curMillis - prevStepMillis);` on `singleStep()`).

This means that any increment in speed will have to be by reducing multiples of 3 ms, and interval below 3 ms will be max velocity. The current movement is quite smooth but is not as fast as I would like (and the 3 ms increment is tricky). If possible, I would like to keep the microstepping (currently at 16) but be able to execute the step order faster (maybe every 0.1 ms) with a finer speed control (maybe 100 microsecond interval)

My question is:

Is 3 ms an acceptable time for this script? How can I know what’s taking it so long? Is there something to optimize ?

spinning_disk.ino (4.07 KB)

``````// PINS //
int stepPin = 6;  //PUL -Pulse
int dirPin = 7; //DIR -Direction
int enPin = 8;  //ENA -Enable
// LED FOR VISUAL FEEDBACK
int LED = 13;

// -----------------------------

// VARIABLES //

float currentStep = 0.0; // placeholder for current step
int stepSpeed = 10;      // milliseconds that take to make a step // deprecated
int maxSteps = 1000;      // max numebr of steps (200 steps is 360 degree rotation).
// Keep in mind microstepping adjustment might be needed
boolean rotation = 0;    // change here rotation == 1 is "HIGH", motor clockwise
// rotation == 0 is counter clockwise (that's what we want)

// -- time variables -- //
unsigned long curMillis;
unsigned long prevStepMillis = 0;
unsigned long millisBetweenSteps = 1; // milliseconds that take to make a step

// VOLTAGE ///

int voltagePin = A0; // Voltage reading
int voltageRead = 0;  // variable to store the value read, needs to be remaped
float voltage = 0; // mapped voltage goes from 0 to 1

// --------------------------

// VOLTAGE SENSOR RESISTORS //

// we are using R1 = 30KΩ and R2 = 7.5KΩ i.e. a 5 to 1 voltage divider (v_divider)

float R1 = 30000.0;
float R2 = 7500.0;

// This is the factor we need to divide
float factor = (R2/(R1+R2));
float realVoltage = 0; // initialize

// -----------------------------

// MAIN PROGRAM //
void setup(){
Serial.begin(9600);           //  setup serial
//Sets the pins as Outputs
pinMode(stepPin, OUTPUT);
pinMode(dirPin, OUTPUT);
pinMode(enPin, OUTPUT);
// this engages the motor
digitalWrite(enPin, LOW);

pinMode(LED, OUTPUT);
pinMode(voltagePin, INPUT);
// Enables the motor direction to move
// we can later add a changeDirection() if we believe it's useful
setDirection();

// The real step is maxSteps * microstepping on the driver (currently at 16)
maxSteps = maxSteps * 16;

}

void loop(){
getVoltage();

// get time
curMillis = millis();

// Actually move direction
if(currentStep < maxSteps){
// moveStepper();
singleStep();
currentStep = currentStep + 1;
//Serial.print(currentStep);
} else {
// disengage motor
digitalWrite(enPin, HIGH);
// stop condition here
}

}

// HELPER FUNCTIONS //

void setDirection(){
if (rotation) {
// do stuff if the condition is true
digitalWrite(dirPin, HIGH);
}
else {
// do stuff if the condition is false
digitalWrite(dirPin, LOW);
}
}

// -----------------------------
// This function is a bad idea because it uses delay()
// delay() stops the loop until it's finished, so we can't sample if we are using this
// kept for informative purposes

void moveStepper(){

// loop
for(int x = 0; x < maxSteps; x++){
digitalWrite(stepPin,HIGH);
delay(floor(stepSpeed/2));
digitalWrite(stepPin,LOW);
delay(floor(stepSpeed/2));
}

}

void singleStep() {

// check how often the steps are being called
// Serial.println(curMillis - prevStepMillis);
if (curMillis - prevStepMillis >= millisBetweenSteps) {
// replace old value with new time
prevStepMillis = curMillis;
// step on-off
digitalWrite(stepPin, HIGH);
digitalWrite(stepPin, LOW);
}
}

// -----------------------------

void getVoltage(){

// The max value read will be 2V at the exit of the voltage sensor
// This comes from the 10V max Novotechnick sensor output divided by 5 in our voltage sensor config

// 2V equals to an analog read signal of 1023/2.5 = 409.2
// We use this value to remap from 0 to 1

// map(value, fromLow, fromHigh, toLow, toHigh) map not working as intended
// voltage = map(voltageRead, 0, 409.2, 0, 1);
realVoltage = (voltageRead /409.2) / factor;

// realVoltage will have a max value of 5V ()
// If we want to match this to the output from the magnetic field sensor (10V)
// We just double that

realVoltage = realVoltage * 2;

Serial.println(realVoltage);          // debug value
//  Serial.println("V");
}

// -----------------------------
``````

This looks WRONG. You are calling singleStep(), which only steps if millisBetweenSteps has elapsed, and record that as a completed step. You seem to be counting steps that don’t occur. You will not reach the expected position if you count steps that don’t occur.

``````  if(currentStep < maxSteps){
// moveStepper();
singleStep();
currentStep = currentStep + 1;
//Serial.print(currentStep);
}
``````

You should get rid of the Serial.println() in singleStep(). That is probably what slows down you sketch.

Thank you! That's indeed a good catch, I hadn't realized because my time between steps was always to low. I was always below 3 ms and I added the print line to try to catch what was going on with it. I was trying to run it at 0.01 ms, 0.1 ms and 1 ms and everything went at the same speed. Your comment is useful, I am now updating the step inside singleStep().

For my purposes, I need to print voltage out via serial print so I would hope that printing command is not the problem.

matiasandina: For my purposes, I need to print voltage out via serial print so I would hope that printing command is not the problem.

How often do you print out the voltage and how many characters do you print? At 9600 baud you can print an average of about 1 character per millisecond. Try any faster than that and the output buffer will fill up and you will have to wait a full millisecond for each character you print. You could use a higher baud rate. My favorite is 115200.

Awesome! such a newbie that I didn’t realize the baud rate would mess with this, I’m so used to using the 9600 that I don’t normally thing about it. Now, it looping in the tens of microseconds 