Introduction: Automated Titration Machine
Titration is normally a labor intensive, time consuming process that involves a trained chemist or technician. We live in the best period ever for makers; electronics are modular, prototyping is rapid, and information is readily available. Using CAD modeling, 3d printing, an arduino development board, and some ingenuity, we are going to automated this time consuming process.
Step 1: Materials and Resources.
We will using the following items and devices in this project:
- An Arduino development board
- Easy stepper driver * 2
- Nema 16 stepper motor
- Peristaltic pump head coupled to stepper motor
- 6mm OD/4mm ID tubing
- Any threaded rod
- Various Makerbot and FlashForge 3D printers
- AutoDesk Inventor
- Atlas Scientific pH probe and circuit
Step 2: CAD Modeling
The design of the titrator is pretty open to your creativity. As long as there is an area to mount a nozzle and a pH probe above a beaker, then the unit will work.
However, my project was limited to a specific box type. I also chose to have my sensor and nozzle array actuate up and down as to prevent accidental damage to the delicate probe, and make the lives of the users easier. Also, it looks kinda cool.
Since I was utilizing 3d printing, I tried to optimize my design the best I could for the printers. For example, try to avoid trailing ledges and extrusions that extend far from the base of structure. This will require the printer to create supports, which require quite a bit of post processing to get a nice finish. Also, since 3D printing is all about convenience, I had all my ports and opening printed, to avoid fabrication time.
Step 3: Circuit Design
As show in the diagram:
The pump is powered by a stepper driver with the "step" pin being connected to pin 9 on the Arduino. We don't use the direction pin since we aren't interested in reversing our pump flow.
The stepper motor responsible for actuating our array up and down in powered by the second stepper driver. For this setup, we use both the step and direction pins, since we need to reverse the rotation of the threaded rod upon completion of the test. Step is connected to pin 7, and direction is connected to pin 7.
It is important to note that the stepper motors require a 12v DC source.
The pH circuit has both a tx and rx pin requirement. Rx is connected to pin 4, and tx is connected to pin 5. VCC and the top ground are connected to the 5v source from the arduino, as well as the arduino ground. The other two pins, ground and PRB connect to the BNC connector on your pH probe.
Step 4: Code
I used the demonstration code from Atlas Scientific for the pH circuit, since it works great. It is important to note that you need to experimentally validate your pump. To do this, hook one end of your pump to a container of water, and the other end to a graduated cylinder. Tell the pump to run for 4000 steps, and record the volume in excel. Do this AT LEAST 3 times, but the more trails, the more accurate your pump. Once you are happy with your runs, average all your tabulated volumes, and divide that by 4000. This is the volume of a single step of your motor.
//By:Kahveh Saramout - Chemical Engineer, Cand
// 12/10/2015 //pH code contributed by atlas scientific // MakeCourse - University of South Florida
#include //we have to include the SoftwareSerial library, or else we can't use it. #define rx 4 //define what pin rx is going to be. #define tx 5 //define what pin tx is going to be.
SoftwareSerial myserial(rx, tx); //define how the soft serial port is going to work.
int dirPin2 = 6; int steppin2 = 7; int dirpin = 1; int steppin = 9; int prep = 8; int x = 1; int y=0; float vol_step = 0.205;
String inputstring = ""; //a string to hold incoming data from the PC String sensorstring = ""; //a string to hold the data from the Atlas Scientific product boolean input_stringcomplete = false; //have we received all the data from the PC boolean sensor_stringcomplete = false //have we received all the data from the Atlas Scientific product float ph; //used to hold a floating point number that is the pH.
void setup() { Serial.begin(9600); //set baud rate for the hardware serial port_0 to 9600 myserial.begin(9600); //set baud rate for software serial port_3 to 9600 inputstring.reserve(10); //set aside some bytes for receiving data from the PC sensorstring.reserve(30); //set aside some bytes for receiving data from Atlas Scientific product
pinMode(dirpin, OUTPUT); pinMode(steppin, OUTPUT); pinMode(prep, INPUT); pinMode(dirPin2, OUTPUT); pinMode(steppin2, OUTPUT); } void serialEvent() { //if the hardware serial port_0 receives a char char inchar = (char)Serial.read(); //get the char we just received inputstring += inchar; //add it to the inputString if (inchar == '\r') { input_stringcomplete = true; //if the incoming character is a , set the flag } }
void loop() { if (x <= 1){ Serial.println(y); long j;
for (j = 0; j<8360; j++) // Iterate for 8360 microsteps. { digitalWrite(dirPin2, HIGH); digitalWrite(steppin2, LOW); // This LOW to HIGH change is what creates the digitalWrite(steppin2, HIGH); // "Rising Edge" so the easydriver knows to when to step. delayMicroseconds(150); // This delay time is close to top speed for this }y++;} if (input_stringcomplete) { //if a string from the PC has been received in its entirety myserial.print(inputstring); //send that string to the Atlas Scientific product inputstring = ""; //clear the string input_stringcomplete = false; //reset the flag used to tell if we have received a completed string from the PC }
if (myserial.available() > 0) { //if we see that the Atlas Scientific product has sent a character. char inchar = (char)myserial.read(); //get the char we just received sensorstring += inchar;
if (inchar == '\r') { sensor_stringcomplete = true; //if the incoming character is a , set the flag } }
if (sensor_stringcomplete) { //if a string from the Atlas Scientific product has been received in its entirety Serial.println("pH: "); //Serial.println(sensorstring); //send that string to the PC's serial monitor ph = sensorstring.toFloat(); Serial.println(ph);//convert the string to a floating point number so it can be evaluated by the Arduino
long i;
for (i = 0; i<1928; i++) // Iterate for 1928 microsteps. { digitalWrite(steppin, LOW); // This LOW to HIGH change is what creates the digitalWrite(steppin, HIGH); // "Rising Edge" so the easydriver knows to when to step. delayMicroseconds(200); // This delay time is close to top speed for this } delay(1000);// particular motor. Any faster the motor stalls. x++; Serial.println("Number of cycles: "); Serial.println(x); //prints 3 of cycles Serial.println("Volume: "); Serial.println(vol_step*x); //calculates our total volume
if (ph <= 6.999) { //if the pH is less than or equal to 6.999 //Serial.println("low"); //print "low" this is demonstrating that the Arduino is evaluating the pH as a number and not as a string } Serial.println(" --------------------- "); sensorstring = ""; //clear the string: sensor_stringcomplete = false; //reset the flag used to tell if we have received a completed string from the Atlas Scientific product } if (x >= 60) { // 60 cycles and we are finished! this is how we wrap up. long k; for (k = 0; k<50370; k++) // Iterate for 50370 microsteps. { digitalWrite(dirPin2, LOW); digitalWrite(steppin2, LOW); // This LOW to HIGH change is what creates the digitalWrite(steppin2, HIGH); // "Rising Edge" so the easydriver knows to when to step. delayMicroseconds(150); // This delay time is close to top speed for this } while (x >= 60) { // Do nothing };}
Step 5: Make It Better!
You have all this useful information, but your doing nothing with it!
Use a data capture shield on your arduino to record the serial port and use the data in excel.
Or in my case, use Matlab to capture the serial output and preform all your calculations for you!
Sorry guys, can't share this code =p