3 stepper motors with different variable speed - solved

Hi
I have problem with my project. Actually I want to run 3 stepper motors with 3 different speed through 3 pots, the first pot adjust the speed of the first stepper motor, the speed of the second stepper motor should be multiple (by the second pot) of the first motor, and the speed of the 3rd motor is the multiple (by the 3rd pot) of the 2nd motor. for example:
if
0<1st motor speed <x (speed changes by pot1)
then
0<2nd motor speed <1st motor speed (speed changes by pot2)
and
0<3rd motor speed <2nd motor speed (speed changes by pot3)

the problem is I need lcd.print for several variables which cause some lag on stepper motors rotation. The code is as follows:


#include <EEPROM.h>
#include <Wire.h> 
#include <LiquidCrystal_I2C.h>
#include <math.h>
#include "HX711.h"
#include <MsTimer2.h>


// variables and definitions

      //Important parameter, set to match environment
          const int dt = 500; // [ms] time constant in milliseconds (controller clock rate = 1/(dt/1000) [Hz])
          #define SetTemp 62.8 // [degC] set temperature in DegC
          #define MinTemp 20 // [degC] minimum expected temperature (needed for rescaling inputs)
          #define MaxTemp 65 // [degC] maximum allowed temperature, over which heater is turned off (needed for rescaling inputs)
          int SetTime = 1800; // [s] timer in seconds, if reached, running stops [Default: 1800]

      float s_integral = 0;

float previous_error = 0;
  //Inititalization
    //target temperature reached?
       bool bInRange = 0;

    //ticks per ms
       int TicksPerMS = floor(1000/dt);

    //Initialize PID variables:
      
      //control parameters - editing not recommended     
          double K_P_ctrl = 15; //proportional gain
          double K_I_ctrl = 0; //integral gain (set to lower values i.e. 10^-3)
          double K_D_ctrl = 0; //derivative gain
          
          
    #define LOADCELL_DOUT_PIN  1    //loadcell DT pin
    #define LOADCELL_SCK_PIN  2       //loadcell SCK pin
    static int pinA = 3; // rotary encoder Our first hardware interrupt pin is digital pin 2
   static int pinB = 4; // rotary encoder Our second hardware interrupt pin is digital pin 3
   const byte buttonPin = 5; //  rotary encoder push button
   int swtu = 7;  // switch up is at pin 7
  int swtd = 6;   // switch down is at pin 6
      byte stepPin1 = 8;
    byte stepPin2 = 9;
    byte stepPin3 = 10;
    int led =13; // led is at pin
   
    const byte ANALOG_IN1 = A0;
    const byte ANALOG_IN2 = A1;
    const byte ANALOG_IN3 = A2;
   int tempPin = A3;  // make variables// thermistor is at A3
   //A4 and A5 are LCD pins
   #define NUMAMOSTRAS 25 
  int amostra[NUMAMOSTRAS];
  int i;

  #define NUMAMOSTRAS1 10
  int amostra1[NUMAMOSTRAS1];
  int i1;
  #define NUMAMOSTRAS2 10 
  int amostra2[NUMAMOSTRAS2];
  int i2;
  #define NUMAMOSTRAS3 10 
  int amostra3[NUMAMOSTRAS3];
  int i3;
   
volatile int currentStep = 0; 

unsigned long currentMillis = 0;    // stores the value of millis() in each iteration of loop()
unsigned long currentMillis1 = 0;
unsigned long previousMillis = 0;
unsigned long previousMillis1 = 0;
unsigned long previousMillis2 = 0;
unsigned long previousMillis3 = 0;
unsigned long previousMillis4 = 0;
int speed1=0;
int speed2=0;
int speed3=0;



float temp;  // make a variable called temp
float settemp; // make a variable called temp

//LiquidCrystal lcd(12, 11, 5, 4, 3, 2); // lcd is at 12,11,5,4,3,2
LiquidCrystal_I2C lcd(0x27, 16, 2);
float c1 = 1.009249522e-03, c2 = 2.378405444e-04, c3 = 2.019202697e-07;

int Vo;
float R1 = 10000;
float logR2, R2, T;
int MaxSpeed = 5000;
int gear1 = 10;
int gear2 = 10;
int ratio1 =0;
int ratio2 =0;

int Acceleration = 1000;
int Analog_1 = 0; //x-axis value
int Analog_2 = 0; //y-axis value
int Analog_3 = 0; //r-axis value

int Analog_1_AVG = 0; //x-axis value average
int Analog_2_AVG = 0; //y-axis value average
int Analog_3_AVG = 0; //r-axis value average

int Analog_3_Value = 0; //this is used for the PWM value



void setup()
{  
  MsTimer2::set(2, fulash_Steps); // set the timer interrupt period to 1 ms
  MsTimer2::start(); // enable timer interrupt
  pinMode (led,OUTPUT);  // make led or pin13 an output
  pinMode(stepPin1, OUTPUT);
  pinMode(stepPin2, OUTPUT);
  pinMode(stepPin3, OUTPUT);
 
  Serial.begin (9600); // set the serial monitor tx and rx speed
  lcd.init();

lcd.backlight();
  lcd.setCursor(0,0); // set the cursor to colum 0 row 0
  lcd.print("hello, world!"); // display hello world for 1 second
  lcd.clear(); // clear the lcd
  EEPROM.read (1); // make the eeprom or atmega328 memory address 1
 }

void loop()
{
  currentMillis = millis();
 currentMillis1 = currentStep;
  Temp();
Control_PID(T); // call controller algorithm

singleStep1();
singleStep2();
singleStep3();
}

void singleStep1() {
speed1=0;
for (i1=0; i1< NUMAMOSTRAS1; i1++) {
speed1 = analogRead(ANALOG_IN1);
amostra1[i1] = speed1;
}

for (i1=0; i1< NUMAMOSTRAS1; i1++) {
speed1 += amostra1[i1];
}
speed1 /= NUMAMOSTRAS1;

   speed1 = map (speed1,0,1023,1,100) ;

    if (currentMillis1 - previousMillis2 >= speed1) {
           
        previousMillis2 = currentMillis1;
        digitalWrite(stepPin1, HIGH);
        digitalWrite(stepPin1, LOW);
    }
}

void singleStep2() {

speed2=0;
for (i2=0; i2< NUMAMOSTRAS2; i2++) {
speed2 = analogRead(ANALOG_IN2);
amostra2[i2] = speed2;

}

for (i2=0; i2< NUMAMOSTRAS2; i2++) {
speed2 += amostra2[i2];
}
speed2 /= NUMAMOSTRAS2;



   speed2 = map (speed2,0,1023,1,speed1) ;
      
ratio1 =speed1 / speed2;
SetPinFrequency(stepPin2, 30); //setting the frequency to 10 Hz
pwmWrite(stepPin2, 127);
    if (currentMillis1 - previousMillis3 >= speed2) {
   
        previousMillis3 = currentMillis1;
    }
}

void singleStep3() {

speed3=0;
for (i3=0; i3< NUMAMOSTRAS3; i3++) {
speed3 = analogRead(ANALOG_IN3);
amostra3[i3] = speed3;

}

for (i3=0; i3< NUMAMOSTRAS3; i3++) {
speed3 += amostra3[i3];
}
speed3 /= NUMAMOSTRAS3;

   speed3 = map (speed3,0,1023,1,speed2) ;

  ratio2 =speed2 / speed3;

    if (currentMillis1 - previousMillis4 >= speed3) {
         
        previousMillis4 = currentMillis1;
        analogWrite(stepPin3, 127);
        
    }
}

void Temp() {
Vo=0;
for (i=0; i< NUMAMOSTRAS; i++) {
Vo = analogRead(tempPin);
amostra[i] = Vo;
}
for (i=0; i< NUMAMOSTRAS; i++) {
Vo += amostra[i];
}
Vo /= NUMAMOSTRAS;

  R2 = R1 * (1023.0 / (float)Vo - 1.0);
  logR2 = log(R2);
  T = (1.0 / (c1 + c2*logR2 + c3*logR2*logR2*logR2));
  T = T - 273.15;

  settemp = EEPROM.read(1); // read the settemp on the eeprom
  
  if             // if we se the switch up pin reading on 1 or 5 volts
    (digitalRead(swtu)== 1 )
  {
    settemp ++  // add one to the settemp, the settemp is the ideal temperature for you
      ;
  }

else{// other wise do nothing

}

if
(digitalRead (swtd) == 1)// if we detect a 1 on the other switch pin
{
  (settemp --);// subtract one fromm the settemp

}
else {
// else, do nothing
}

if (currentMillis - previousMillis >= 800)
{
  lcd.clear();
lcd.setCursor (0,0); // set the cursor to 0,0
  lcd.print (T);  // Print the current temp in f
  lcd.print ('C');

lcd.setCursor (7,0); // set the cursor to 0,1
lcd.print ("To"); // Print set to and your ideal temperature in f
lcd.print (settemp);
lcd.print ('C');

lcd.setCursor (0,1); // set the cursor to 0,1
lcd.print ("A"); // Print set to and your ideal temperature in f
lcd.print (speed1);

lcd.setCursor (5,1); // set the cursor to 0,1
lcd.print (" B"); // Print set to and your ideal temperature in f
lcd.print (ratio1);

lcd.setCursor (10,1); // set the cursor to 0,1
lcd.print (" C"); // Print set to and your ideal temperature in f
lcd.print (ratio2);

  previousMillis=currentMillis;
}
if (currentMillis - previousMillis1 >= 1000)
{
EEPROM.write (1,settemp); /* write the most recent settemp in eeprom data stoage
//  so that if the power is disconnected, you settemp is saved!*/
previousMillis1=currentMillis;
}
return Temp;

}

//PID controller code
void Control_PID(double iTemp) {
      //Overheat protection
          if(iTemp>(settemp+5)){
            analogWrite(led, 0);
            return;
          }
        
      //In range? If in range, maybe turn on LED?
          if((iTemp) >= settemp){
            if(bInRange==0){
              //digitalWrite(LEDPin, HIGH); 
              bInRange=1;
            }
          }else{
            if(bInRange==1){
              //digitalWrite(LEDPin, LOW); 
              bInRange=0;
            }
          }
          
        
        //PID subroutine
          float err = settemp - iTemp;
          
          s_integral += err*dt;
          
          float s_derivative = (err - previous_error)/dt;
          
          int U_in_ctrl = (K_P_ctrl*err + K_I_ctrl*s_integral + K_D_ctrl*s_derivative)/(MaxTemp-MinTemp)*255;
          previous_error = err;
                 
          
        // put voltage to output and write value to serial monitor

            
            if (U_in_ctrl<=255){
               if (U_in_ctrl > 0){
                  analogWrite(led, U_in_ctrl);
         
               }           
               else
               {
                  analogWrite(led, 1);

               }
            }
            else{
               analogWrite(led,255);
   
            }                   
    }

    
    void fulash_Steps(){

        currentStep++;
}

In the code I used MsTimer2 lib to get ride of the lag but it is not totally successful.
Also I try to update the LCD 800ms using if (currentMillis - previousMillis >= 800) without success.
please note that I also included some code for thermostat and heater with PID control.
Any Idea to get ride of interruption caused by lcd.print?

Thank you

You could use my MobaTools lib to drive your steppers. This lib creates the step pulses by timer interrupts. You don't have to bother with step generation in loop. Therefore the steps are not influenced by delays in the loop. Simply set the speed if you want it to change.

Great job, let me study documentation of your lib first.

Yeah, that's always a good idea :sunglasses:

I would start with something like this:

const unsigned long MaxStepsPerSecond = 1000;

void loop()
{
  unsigned long currenMicros = micros();

  unsigned long Speed1 = (analogRead(A0) * MaxStepsPerSecond) / 1024;
  unsigned long Speed2 = (analogRead(A1) * Speed1) / 1024;
  unsigned long Speed3 = (analogRead(A2) * Speed2) / 1024;

  if (Speed1 > 0)
  {
    unsigned long microsPerHalfStep = 500000ul / Speed1;
    static lastMicros = 0;
    if (currenMicros - lastMicros >=  microsPerHalfStep)
    {
      lastMicros = currentMicros;
      digitalWrite(S1Pin, !digitalRead(S1Pin)); // Toggle
    }
  }

  if (Speed2 > 0)
  {
    unsigned long microsPerHalfStep = 500000ul / Speed2;
    static lastMicros = 0;
    if (currenMicros - lastMicros >=  microsPerHalfStep)
    {
      lastMicros = currentMicros;
      digitalWrite(S2Pin, !digitalRead(S2Pin)); // Toggle
    }
  }

  if (Speed3 > 0)
  {
    unsigned long microsPerHalfStep = 500000ul / Speed2;
    static lastMicros = 0;
    if (currenMicros - lastMicros >=  microsPerHalfStep)
    {
      lastMicros = currentMicros;
      digitalWrite(S3Pin, !digitalRead(S3Pin)); // Toggle
    }
  }
}

Thank you MicroBahner, your Lib did the magic.

thank you Johnwasser

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