Syringe micro pump

Hello Arduino community,

I have a stepper motor, easy driver, an arduino nano and an lcd screen (the one provided with arduino start up pack).
I would like to know, if it is possible to command the revolution of the motor (back and forth), and the time to achieve these revolutions (i.e. if i want 100µl of liquid in one minute for example, can i select it on the screen and press play to reach that action ? ).

i understand that i have to go with accelstep library, but im a noob, and my knowledge stopped there.

Would someone help me with that ?

thank you in advance

Ben.

YES.

But you need a reasonably complex program to achieve all that.

Break your project into several small parts and create short programs to learn each part. For instance to move the stepper, to manage time and to use the LCD screen.

If it was my project I would leave the LCD stuff until last and just use the Serial Monitor for input and output at the early stages. That will make it easier to get help here because not everyone has an LCD device and the LCD code tends to get in the way.

...R
Planning and Implementing a Program
Stepper Motor Basics

Thank you Robin for your quick answer.

i will read and be back after i learn how things are working !

Yeah.

Assuming you are using a threaded rod attached to the stepper motor, you can determine the pitch of the rod (the distance a but will move after 1 turn).

A general pitch may be say 0.5mm on a fine M5 (5mm diameter rod).

So after a 360 degree turn of the stepper/rod, a nut will move 0.5mm.
Most steppers have around 200 steps per revolution (again...check your specs).

From that we get:

Travel = pitch of rod * (steps taken / steps per revolution)

You can then, with knowing the length of the syringe between the "full" and "empty" marks get a conversion ratio for the distance:volume.

Ratio of Conversion (ml/mm) = volume of syringe / length of syringe

Volume Ejected = Ratio of Conversion * Travel

Then re-arrange the lot to get the volume ejected per motor step:

Volume Ejected = (Volume of Syringe / length of syringe) * pitch of rod * (1 / steps per revolution)

Par Example:

Volume Ejected (ml) in 8 steps = (10ml / 100mm) * 0.5 * (8/200) = 0.1 * 0.5 * 0.005 = 0.002 ml

A second way to do this would be with a very accurate balance (microgram range) and seeing how many turns it takes to eject the whole 1ml of water (water is 1g/cm3 = 1ml) .

Following the reading of your useful post, if i am right, the code for the stepper motor driven by user input should use this "kind of" command :

user input (volume);
user input (time);
convert input volume in # of revolution;
convert input time in rpm;
flash greenled;
waiting user push a button to start moving;
if button pushed then begin to move;
fix green led until moves are done.

am i right ?

Aw, i didnt see Johnny's post before sending mine.
So, thank you johnny for your answer. It will be useful when i will be ok with the code. I know that i will struggle with it but im pretty sure it will be very useful for other kind of application to know how to buil a code properly.

benlatafff:
am i right ?

That sounds sensible. But it will need to be verified by experiment :slight_smile:

...R

Ok, so i have know this basic code for moving the motor, it seems to compil.

#include <AccelStepper.h>

AccelStepper motor(1,7,8); // Stepper Driver mode = 1 step pin = 7 dir pin = 8
int inject = 3;    // inject
int refill = 4;  //refill

void setup() {


        motor.setMaxSpeed(1000);
        motor.setAcceleration(500);
        motor.setMinPulseWidth(100);
        motor.setCurrentPosition(0);
       
 pinMode(inject, INPUT);
 pinMode(refill, INPUT);
 
        Serial.begin(9600);

}

void loop() {

  //if inject button is pressed, then inject
  
 if (digitalRead(inject) == HIGH) {        
            motor.moveTo(5000);             
 pushPiston();       
   }
// if refill button is pressed, then refill
 if (digitalRead(refill) == HIGH) {      
            motor.moveTo(0);                
 pullPiston();       
   }  
  
 
Serial.println(motor.currentPosition()); //print the actual position of motor
}

void pushPiston() {
        
        while (digitalRead(inject) == HIGH) {  
 
 if (motor.currentPosition() != 5000) { //check that the motor is not to the upper limit
 
 motor.run();
 }
                
          }
        
}


void pullPiston() {
 
              
 while (digitalRead(refill) == HIGH) {
 
 if (motor.currentPosition() != 0) { //check that the motor is not to the lower limit

 motor.run();
 }
 }
        
}

It seems to compile.

Now, i have to deal with the user define movement via serial communication, it seems really tough !
any advice ?

benlatafff:
Now, i have to deal with the user define movement via serial communication, it seems really tough !
any advice ?

Put your stepper program to one side and write a program to receive Serial data. See Serial Input Basics. There is also a user-input part in Planning and implementing ...

To bring the two concepts together you need to consider what information your stepper program needs in order to do what you want. Think of having a variable (or 2 or 3) that is shared by the the stepper part of the program and the serial input part of the program to provide an interface between the two parts.

And then figure out how to receive something suitable. It may make sense to receive a command in a human useable format (eg 'G') for go and have the Arduino translate that into a stepper command.

...R

am i on the right way ?

#include <AccelStepper.h>

int stepperDirection;
int stepperSpeed;

AccelStepper motor(1,7,8); // Stepper Driver mode = 1 step pin = 7 dir pin = 8
int inject = 3;    // inject
int refill = 4;  //refill

void setup (){
    motor.setMaxSpeed(1000);
        motor.setAcceleration(500);
        motor.setMinPulseWidth(100);
        motor.setCurrentPosition(0);
       
	pinMode(inject, INPUT);
	pinMode(refill, INPUT);
  Serial.begin(9600);
}
  void loop(){
    if (Serial.available() > 0) {
      stepperDirection = Serial.read();
      if (stepperDirection == 1) {
         pushPiston();
   }

      if (stepperDirection == 0) 
        pullPiston();
      }
    
    
  
   //if inject button is pressed, then inject
  
	if (digitalRead(inject) == HIGH) {        
    	        motor.moveTo(7500);             
		pushPiston();  		    	
  	}
// if refill button is pressed, then refill
	if (digitalRead(refill) == HIGH) {      
    	        motor.moveTo(0);                
		pullPiston();  		    	
  	}  
  
	
Serial.println(motor.currentPosition()); //print the actual position of motor
}

void pushPiston() {
	        
        while (digitalRead(inject) == HIGH) {  
		
		if (motor.currentPosition() != 7500) { //check that the motor is not to the upper limit
			
			motor.run();
		}
                
          }
        
}


void pullPiston() {
	
              
	while (digitalRead(refill) == HIGH) {
		
		if (motor.currentPosition() != 0) { //check that the motor is not to the lower limit

			motor.run();
		}
}
}

but im not sure that arduino can handle + and - sign ? is there a tricks to convert it into something that arduino understand ?

For the way you have your code organized maybe motor.runToPosition() would be more suitable.

For motor.run() to work it must be called very frequently - faster than the motor is intended to step - and that would need a different approach to your program.

...R

it cant be an int inside motor.runTOPosition() ?

ok is it better know ?

#include <AccelStepper.h>

int stepperDirection;
int stepperSpeed;
int pistonLimit = 3500;

AccelStepper motor(1,7,8); // Stepper Driver mode = 1 step pin = 7 dir pin = 8
int inject = 3;    // inject
int refill = 4;  //refill

void setup (){
    motor.setMaxSpeed(100);
        motor.setAcceleration(100);
        motor.setMinPulseWidth(100);
        motor.setCurrentPosition(0);
       
	pinMode(inject, INPUT_PULLUP);
	pinMode(refill, INPUT_PULLUP);
  Serial.begin(9600);
}
  void loop(){
    if (Serial.available() > 0) {
      stepperDirection = Serial.read();
      if (stepperDirection == 1) {
         pushPiston();
   }

      if (stepperDirection == 0) 
        pullPiston();
      }
    
    
  
     //if inject button is pressed, then inject
  
	if (digitalRead(inject) == HIGH) {        
    	        motor.runToPosition();             
		pushPiston();  		    	
  	}
    // if refill button is pressed, then refill
	if (digitalRead(refill) == HIGH) { 
              while (motor.currentPosition() != 0);
    	        motor.runToPosition();                
		    pullPiston();  		    	
  	}  
  
	
Serial.println(motor.currentPosition()); //print the actual position of motor
}

void pushPiston() {
	        
        while (digitalRead(inject) == HIGH) {  
		
		if (motor.currentPosition() != 3500) { //check that the motor is not to the upper limit
			
			motor.moveTo(stepperDirection);
		}
                
          }
        
}


void pullPiston() {
	
              
	while (digitalRead(refill) == HIGH) {
		
		if (motor.currentPosition() != 0) { //check that the motor is not to the lower limit

			motor.moveTo(stepperDirection);

		}
}
}

Have you studied the AccelStepper documentation?

The library has two broad concepts. You set a destination position for the motor. You get it to move to that position.

There are two general approaches to getting it to move - blocking and non-blocking. The blocking moves motor.runToPosition() will cause the motor to go all the way to the destination without giving you a chance to intervene. So you don't need code like

while (motor.currentPosition() != 0);
    	        motor.runToPosition();

You just need the second of these lines

Also this piece

       motor.runToPosition();             
		pushPiston();

seems to put the cart before the horse - telling it to move before telling it where to move to.

Write a short program that just enables you to learn how the library functions work.

...R
PS If you want to use the non-blocking approach (motor.run() ) you will need a substantial re-write of your program

Thank you very much Robin, i thought i did, but obviously i didnt understand these concepts.

I will try again.