Skip to content

Instantly share code, notes, and snippets.

@Craigson
Created October 9, 2015 19:13
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save Craigson/5ecb810bf592d86a5bda to your computer and use it in GitHub Desktop.
Save Craigson/5ecb810bf592d86a5bda to your computer and use it in GitHub Desktop.
Firmware for the syringe pump control interface
/*
* Stepper:
* coil A+ yellow
* coil A- red
* coil B+ grey
* coil B- green
*/
#define stp 2 //step pin
#define dir 3 //direction pin
#define MS1 4 //step resolution pin 1
#define MS2 5 //step resolution pin 2
#define EN 6 //enable pin
#define MP 8
#define FWD 9 //fwd button input pin
#define RVRS 10 //reverse button input pin
#define MTR 13 //vibration motor pin
char user_input;
int state;
double drop_diameter; //variable to store the value the user enters
double drop_volume;
double cylinder_volume;
double syringe_id; //variable for storing the inner diameter of the syringe
double plunger_travel_distance;
double travel_per_revolution; //variable to store the distance travelled by the plunger per 360' rotation
double rev_count;
double number_of_steps;
int rounded_steps, num_microsteps;
double remainder;
int buttonPushCounter = 0; // counter for the number of button presses
int buttonState = 0; // current state of the button
int lastButtonState = 0;
String inString = "";
bool buttonOn;
char TempString[10];
//volume of cylinder: V = PI * r^2 * h
//volume of drop: V = 4/3 * PI * r^3
//rod travel is 1.5875mm per turn
//syringe inner diameter is 4.62mm
void setup() {
pinMode(stp, OUTPUT);
pinMode(dir, OUTPUT);
pinMode(MS1, OUTPUT);
pinMode(MS2, OUTPUT);
pinMode(EN, OUTPUT);
pinMode(MTR, OUTPUT);
pinMode(FWD, INPUT);
pinMode(RVRS, INPUT);
pinMode(12, OUTPUT);
digitalWrite(MTR, LOW);
digitalWrite(FWD, LOW);
digitalWrite(RVRS, LOW);
digitalWrite(12, LOW);
resetEDPins(); //Set step, direction, microstep and enable pins to default states
delay(500);
Serial.begin(9600); //Open Serial connection for debugging
delay(500);
Serial.println("Begin motor control");
Serial.println();
Serial.println("Enter the desired drop diameter in mm (accurate to 2 decimal places).");
Serial.println("\n");
Serial.println("** For example, if a drop with a 4mm diameter is required, enter 4.00 **");
//DEFINE COMPONENT VALUES
syringe_id = 4.62; //in mm
travel_per_revolution = 1.5875; // in mm;
}
void loop() {
//READ THE BUTTON STATE
buttonState = digitalRead(FWD);
if (buttonState != lastButtonState) {
if (digitalRead(FWD) == HIGH)
{
executeFullSteps(300);
resetEDPins();
}
}
lastButtonState = buttonState;
//WAIT FOR USER INPUT
while (Serial.available()) {
Serial.println("--------------------------------------------");
Serial.println("\n");
String str = Serial.readStringUntil('\n');
drop_diameter = (double)str.toFloat();
TempString[10]; // CHARACTER ARRAY TO STORE DOUBLE VALUES FOR PRINTING
// dtostrf( [doubleVar] , [sizeBeforePoint] , [sizeAfterPoint] , [WhereToStoreIt] )
dtostrf(drop_diameter, 2, 8, TempString); //CONVERT DOUBLE TO STRING
String diam = String(TempString); // CAST TO STRING FROM CHAR ARRAY
Serial.print("Required drop diameter: ");
Serial.print(diam);
Serial.print("mm");
Serial.println("\n");
double drop_radius = drop_diameter / 2; // CONVERT TO RADIUS FOR VOLUME CALCULATIONS
digitalWrite(EN, LOW); //Pull enable pin low to allow motor control
//volume of a sphere: V = (4/3)*PI*r^3
drop_volume = (4 * PI * (pow( ( drop_diameter / 2), 3 )) ) / 3; //in mm^3
dtostrf(drop_volume, 2, 8, TempString);
// dtostrf( [doubleVar] , [sizeBeforePoint] , [sizeAfterPoint] , [WhereToStoreIt] )
String drop_vol = String(TempString); // cast it to string from char
Serial.print("drop volume: ");
Serial.print(drop_vol);
Serial.println("uLitres");
/*
the volume of water displaced by the syringe plunger will be equal
to the volume of the desired droplet, thus sphere_volume = cylinder_volume.
volume of a cylinder: V = PI * r^2 * h, where h = plunger_travel_distance
therefore, drop_volume = PI * pow( (syringe_id/2), 2) * plunger_travel_distance
therefore, plunger_travel_distance = drop_volume / (PI * pow( (syringe_id/2),2 ) );
*/
plunger_travel_distance = drop_volume / (PI * pow( (syringe_id / 2), 2 ) );
dtostrf(plunger_travel_distance, 2, 8, TempString);
// dtostrf( [doubleVar] , [sizeBeforePoint] , [sizeAfterPoint] , [WhereToStoreIt] )
String trav_dist = String(TempString); // cast it to string from char
Serial.println(" ");
Serial.print("plunger travelled: ");
Serial.print(trav_dist);
Serial.print("mm");
Serial.println("\n");
/*
the stepper motor has a resolution of 200 steps / revolution, while the threaded rod has
a travel of 1/16", or 1.5875mm, per revolution, ie. the plunger travels 1.5875mm per full
revolution (200 steps).
*/
//DETERMINE THE NUMBER OF ROTATIONS
rev_count = plunger_travel_distance / travel_per_revolution;
Serial.print("Number of revolutions: ");
Serial.print(rev_count);
Serial.println("\n");
//CONVERT TO NUMBER OF STEPS REQUIRED
number_of_steps = rev_count * 200;
Serial.print("Total number of steps: ");
Serial.print(number_of_steps);
Serial.println("\n");
//CONVERT TO INTEGER FOR NUMBER OF FULL STEPS REQUIRED
int rounded_steps = floor(number_of_steps);
Serial.print("Full steps: ");
Serial.print(rounded_steps);
Serial.println("\n");
//USE THE DIFFERENCE TO DETERMINE THE NUMBER OF MICROSTEPS
remainder = number_of_steps - rounded_steps;
//DETERMINE THE NUMBER OF 1/8 MICROSTEPS TO FOLLOW THE FULL STEP
num_microsteps = remainder / 0.125;
Serial.print("1/8 microsteps: ");
Serial.print(num_microsteps);
Serial.println("\n");
//DRIVE THE MOTOR
executeFullSteps(rounded_steps);
if (num_microsteps != 0) {
executeMicroSteps(num_microsteps);
}
//VIBRATE THE VIBRATION MOTOR TO RELEASE THE DROPLET
shakeLoose();
Serial.println("");
Serial.print("plunger moved a total of ");
Serial.print(plunger_travel_distance);
Serial.print("mm to displace ");
Serial.print(drop_volume);
Serial.println("uLitres of water");
Serial.println("\n");
Serial.println("-----------------------------------");
}
//RESET MOTOR PINS
resetEDPins();
inString = "";
}
//Reset Easy Driver pins to default states
void resetEDPins()
{
digitalWrite(stp, LOW);
digitalWrite(dir, LOW);
digitalWrite(MS1, LOW);
digitalWrite(MS2, LOW);
digitalWrite(EN, HIGH);
}
void executeFullSteps(int full_steps)
{
Serial.print("executing ");
Serial.print(full_steps);
Serial.println(" full steps.");
digitalWrite(dir, HIGH); //Pull direction pin low to move "forward"
digitalWrite(MS1, LOW); //Pull MS1, and MS2 low to set logic to full step resolution
digitalWrite(MS2, LOW);
for (int x = 0; x < full_steps; x++) //
{
digitalWrite(stp, HIGH); //Trigger one step forward
delay(5);
digitalWrite(stp, LOW); //Pull step pin low so it can be triggered again
delay(5);
}
}
void executeMicroSteps(int micro_steps)
{
Serial.print("executing ");
Serial.print(micro_steps);
Serial.println(" microsteps.");
digitalWrite(dir, LOW); //Pull direction pin low to move "forward"
digitalWrite(MS1, HIGH); //Pull MS1, and MS2 high to set logic to 1/8th microstep resolution
digitalWrite(MS2, HIGH);
for (int x = 0; x < micro_steps; x++) //
{
digitalWrite(stp, HIGH); //Trigger one step forward
delay(11);
digitalWrite(stp, LOW); //Pull step pin low so it can be triggered again
delay(11);
}
delay(500);
}
void shakeLoose() {
digitalWrite(MTR, HIGH);
delay(2000);
digitalWrite(MTR, LOW);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment