Accuracy problem with stepper motor function

Hi all,

I am building a project of infusion pump for which i want accuracy in volume and time.

I have used stepper motor(NEMA 17) and motor diver shield with arduino mega. I have used accel stepper for micro stepping and parallel updated TFT lcd for display data at every 1 second. But it added some delay in my motor functions. I had used timer interrupt without any delay function for TFT LCD update. Is that any way to overcome this delay if i using motor and LCD at same controller board (arduino mega).

I have also tested that TFT lcd interfacing to arduino mega and motor to arduino UNO. In that case i dont get any delay in infusion of motor function. So is it necessary to interface motor with an isolated controller for better accuracy?

That's all very interesting but if you want help you will have to post your code.

And please use the code button </>so your code looks like thisand is easy to copy to a text editor

...R

[/
void setup()
{
  Serial.begin(9600);
  noInterrupts();           // disable all interrupts
  
  TCCR3A = 0;    //timer interrupt 1seconds//
  TCCR3B = 0;
  TCNT3  = 0;
  OCR3A = 62500;            // compare match register 16MHz/256/1Hz
  TCCR3B |= (1 << WGM12);   // CTC mode
  TCCR3B |= (1 << CS12);    // 256 prescaler 
  TIMSK3 |= (1 << OCIE3A);  // enable timer compare interrupt
  interrupts();             // enable all interrupts
  stepper.setMaxSpeed(1000);
  tft.reset();
  uint16_t identifier = tft.readID(); // this line is used to detect the Driver ID of the LCD. Here Samsung SD060154 LCD  Drvier IC is their
  tft.begin(identifier); // this line is used to start the LCD Driver to communicate
  tft.setRotation(3);
  white_border(); 
}

ISR(TIMER3_COMPA_vect)          // timer compare interrupt service routine
{
    value1 = 1;
   
 }


/****************************************************************************************************************************************************************************/
/*************************************************************  VOID MAIN LOOP()  ********  (STARTS)  ***********************************************************************/
/****************************************************************************************************************************************************************************/
void loop()
{
 TOTAL_VOL_OF_SYRINGE=20;
 INCH_PER_VOL=0.123;
 VOL_TO_INFUSE=1;
 FLOWRATE=60;
 finalpage1();                               //display data value//
 logic = true;
while (logic)
{
  key = keypad.waitForKey();
  Serial.print(key);
  if (key == 'A')
  {
    logic = false;
  }
}
clr_rounded_scrn();
finalpage2();
stepper_run();
}

/****************************************************************************************************************************************************************************/
/************************************************     enter_total_vol_of_syringe_screen()      *************************************************************************************/
/****************************************************************************************************************************************************************************/

unsigned long finalpage1()
{
 tft.fillScreen(BLACK); 
 tft.drawRoundRect (0    ,0   , 320, 40  ,10  , WHITE); // screen rectangle
 tft.drawRoundRect (0    ,39  , 320, 40  ,10  , WHITE); // screen rectangle 
 tft.drawRoundRect (0    ,78  , 320, 40  ,10  , WHITE); // screen rectangle  
 tft.drawRoundRect (0    ,117  , 320, 41  ,10 , WHITE); // screen rectangle  
 tft.drawRoundRect (0    ,157  , 320, 42  ,10 , WHITE); // screen rectangle 
 tft.drawRoundRect (0    ,198  , 320, 42  ,10 , WHITE); // screen rectangle 
/**********************************  Screen Text  **************************************/
 tft.setTextColor(WHITE);
 tft.setTextSize(2);
 tft.setCursor(90, 15);
 tft.print("DATA ENTERED");
 tft.setTextSize(1);
 tft.setCursor(5, 55);
 tft.print("Total Syringe Volume (mL):");
 tft.setCursor(5, 95);
 tft.println("Inch per Volume (inch/mL):");
 tft.setCursor(5,133);
 tft.print("Volume to Dispense (mL):");
 tft.setCursor (5, 175);
 tft.print("Flow Rate (mL/hr):");
 tft.setCursor (5, 215);
 tft.print("Drug:");
 
 /***********************      Inputs from Variables      *********************************/
 
 tft.setTextSize(3); tft.setTextColor(CYAN);
 tft.setCursor(180, 48);
 tft.println(TOTAL_VOL_OF_SYRINGE);  
 tft.setCursor(180, 87);
 tft.print(INCH_PER_VOL,4);
 tft.setCursor(180, 126);
 tft.println(VOL_TO_INFUSE,1);
 tft.setCursor(180, 167);
 tft.println(FLOWRATE,2);
}

unsigned long finalpage2()
{

 tft.drawRoundRect (0    ,0   , 320, 40  ,10  , CYAN); // screen rectangle
 tft.drawRoundRect (0    ,39  , 200, 40  ,10  , CYAN); // screen rectangle 
 tft.drawRoundRect (199  ,39  , 121, 40  ,10  , CYAN); // screen rectangle 
 tft.drawRoundRect (0    ,78  , 241, 40  ,10  , CYAN); // screen rectangle  
 tft.drawRoundRect (240  ,78  , 80, 40  ,10  , CYAN); // screen rectangle 
 tft.drawRoundRect (0    ,117  , 320, 41  ,10  , CYAN); // screen rectangle  
 tft.drawRoundRect (0    ,157  , 320, 42  ,10  , CYAN); // screen rectangle 
 tft.drawRoundRect (0    ,198  , 320, 42  ,10  , CYAN); // screen rectangle 
/**********************************  Screen Text  **************************************/
 
 tft.setTextSize(1);
 tft.setCursor(5, 55);
 tft.print("Rate:");
 tft.setTextSize(2);
 tft.setCursor(230, 52);
 tft.println("mL/hr");
 tft.setTextSize(1); 
 tft.setCursor(5, 95);
 tft.println("Volume to Infuse:");
 tft.setTextSize(2);
 tft.setCursor(270, 90);
 tft.print("mL");
 tft.setCursor(250,170);
 tft.print("mL");
 tft.setTextSize(1);
 tft.setCursor(5,175);
 tft.print("Volume Remaining:");
 tft.setCursor (5, 133);
 tft.print("Time Remaining:");
 tft.setCursor (5, 215);
 tft.print("Drug:");
 tft.setCursor(110, 125);
 tft.setTextSize(3);tft.setTextColor(WHITE);
 tft.print("  h   m   s");
 tft.setTextSize(3); tft.setTextColor(GREEN);
 tft.setCursor(140, 87);
 tft.println(VOL_TO_INFUSE, 1);
 tft.setTextSize(3);
 tft.setCursor(70, 48);
 tft.println(FLOWRATE);
 tft.setCursor (100, 210);
 tft.print("Antracin");
}

//motor function//

unsigned long stepper_run()
{
   STEPSIZE = M;
   STEPS_PER_mL = (TURNS_PER_INCH * INCH_PER_VOL * 3200);
   TARGETSTEPS =  (STEPS_PER_mL * VOL_TO_INFUSE);
   MOTOR_SPEED = ((STEPS_PER_mL * FLOWRATE) / 3600);
   total_time_in_secs = (TARGETSTEPS / MOTOR_SPEED);
   logic = true;
   value2=1;
   while (logic)
   {
     stepper.moveTo(TARGETSTEPS);
     stepper.setSpeed(MOTOR_SPEED);
     stepper.runSpeedToPosition();
      
     if (stepper.currentPosition() == TARGETSTEPS)
     {
       motor.release();
       break;
     }
     time_remaining();
   }
  }

//UPDATE LCD//

  unsigned long time_remaining()
{
 if (value1 == 1 && value2==1)
  {
  total_time_in_secs--;
  hours = total_time_in_secs / 3600;
  minutes = ((total_time_in_secs % 3600) / 60);
  seconds = ((total_time_in_secs % 3600) % 60);      
  double Volv = (FLOWRATE*total_time_in_secs)/3600;                                              //decremented vol
   tft.setTextSize(1);
   tft.setTextColor(WHITE);
   tft.setCursor (5, 133);
   tft.print("Time Remaining"); 
   tft.setCursor(5,175);
   tft.print("Volume Infused:");

   tft.setTextColor(GREEN);
   tft.setTextSize(3);
   tft.setCursor(120, 127); tft.print (hours);tft.setCursor(170,127);              //time_remaing on nrml_operation
   tft.print (":");
   tft.setCursor(185, 127); tft.print (minutes);tft.setCursor(218,127);
   tft.print (":");   
   tft.setCursor(235, 127); tft.print (seconds);
    
    Serial.print("vol");Serial.println(Volv);
    tft.setTextSize(3);
    tft.setTextColor(GREEN);

    tft.setCursor(135,167);
    tft.print(Volv);

    tft.fillRoundRect (90, 127, 200, 30, 20, BLACK);
    tft.fillRoundRect (115, 167, 130, 30, 25, BLACK);  
    tft.fillRoundRect (2, 120, 200, 30, 20, BLACK);
   tft.fillRoundRect (2, 165, 200, 30, 35, BLACK);
    if(total_time_in_secs==0)
   {
    value2 = 0;
  }
   value1=0;
 }
 }
 
 unsigned long clr_rounded_scrn()
{
  tft.fillRoundRect(6, 7, 307, 226, 20, BLACK);  // this line is for Cleaning the above execution on screen
}

unsigned long white_border()
{
  tft.fillScreen(BLACK);
  tft.fillRoundRect (0, 0, 320, 240, 20, WHITE);
  clr_rounded_scrn();
}



]

No, you have to post something that at least compiles!!

ohh, actually i have deleted the initialization portion of code because here i got error that u cannot post more 9000(or some thing else figure)

[/#include <Adafruit_GFX.h>
#include <Adafruit_TFTLCD.h>
#include <Keypad.h>
#include <AFMotor.h>
#include <AccelStepper.h>
#define LCD_CS A3
#define LCD_CD A2
#define LCD_WR A1
#define LCD_RD A0
#define LCD_RESET A4

#define	BLACK   0x0000
#define	BLUE    0x001F
#define	RED     0xF800
#define	GREEN   0x07E0
#define CYAN    0x07FF
#define MAGENTA 0xF81F
#define YELLOW  0xFFE0 
#define WHITE   0xFFFF
#define MAROON  0x8000
#define TEAL    0x0410
#define ORANGE  0x0FFF
#define X       0xFFF0
Adafruit_TFTLCD tft(LCD_CS, LCD_CD, LCD_WR, LCD_RD, LCD_RESET);

AF_Stepper motor(200, 1);  // MOTOR PORT DECLARATION FOR adafruit motor sheild
int M = MICROSTEP;
int I = INTERLEAVE;
int S = SINGLE;
int D = DOUBLE;
float STEPSIZE;
void forwardstep()
{  
  motor.onestep(BACKWARD, STEPSIZE);
}

void backwardstep()
{  
  motor.onestep(FORWARD, STEPSIZE);
}

AccelStepper stepper(forwardstep, backwardstep);
const byte ROWS = 4; // four rows
const byte COLS = 4; // three columns
char keys[ROWS][COLS] = {
  {'1','2','3','A'},
  {'4','5','6','B'},
  {'7','8','9','C'},
  {'.','0','>','Z'}
};

byte rowPins[ROWS] = {45,43,41,39}; //connect to the row pinouts of the keypad
byte colPins[COLS] = {37,35,33,31}; //connect to the column pinouts of the keypad
  
Keypad keypad = Keypad( makeKeymap(keys), rowPins, colPins, ROWS, COLS );

/****************      PIN Configuration      *********************/

int value1,value2;
unsigned long time;
unsigned long hours; 
unsigned long minutes;
unsigned long seconds;

/****************      VARIABLES DECLARATION FOR STEPPER_RUN()     *********************/
float TURNS_PER_INCH = 31.75;

float TARGETSTEPS;
float MOTOR_SPEED;
float STEPS_PER_mL;
/****************      VARIABLES DECLARATION FOR PROGRAM     *********************/
int tempkeycount;
int count=0;
int x= 1;
int decimal = 0;
int keycount = 0;
char key;
boolean logic = true;
char DIGITS[6] ={};
String Rate;
unsigned long total_time_in_secs;

/****************      VARIABLES FOR CALCULATION      *********************/
int TOTAL_VOL_OF_SYRINGE;
double INCH_PER_VOL;
float VOL_TO_INFUSE;
float FLOWRATE;

]

This is the initialization of code with adding accel stepper library can compile it.

Still won't compile, the first character is a [

Understand what the point of code tags is: We can select, copy, paste, compile directly from it

If you make it hard for us to do that, we get less motivated to do it.

If the program is too big (I hope not) you can add the .ino file as an attachment.

...R

OK.
Finally find the attached code hope it will compile this time. :o

CODE.ino (9.26 KB)

In your loop() code you call three functions
finalpage1()
clr_rounded_scrn()
finalpage2()
each of which probably takes a long time and which do not not need to be called hundreds of times per second.

These are almost certainly preventing stepper.run() from being called often enough.

I suspect it would be sufficient to update the TFT screen twice per second.

Also you should try to limit any writing to the TFT screen to the minimum - rather than updating the entire display.

Alternatively, break the TFT update into a few separate functions each of which does part of the screen - but not so much as to delay the generation of steps. The human eye won't notice.

...R

I am not sure if you can call run() in an ISR, that might be the way to finesse the issue completely. (if it
works).

ohk. sorry for late replying (i am on leave for few days).

@Maekt means i have to take another interrupt of few mill or micro seconds and just write run() motor function on that ISR right?

I am trying it and let me inform you.

@Robin2 in my loop after entering stepper_run() function there is a while loop inside that and after that only one function is calling in loop that is time_remaining() function for updating TFT LCD and I have to compulsory
update LCD after 1 second. And yes now in my time remaining function i will only update part of TFT LCD which require to update not entire LCD which might be consume time.