Quick and Ugly Pipette Puller

We needed a pipette puller at work to test out an electrophysiology rig, but didn't have easy access to one, and didn't want to pony up multiple thousands for a commercial one just for testing. We also needed one quickly—publish or perish—and getting approval from purchasing for an expensive piece of equipment takes time, as does shipping. To get things rolling, I whipped this one together from the junk pile over a couple nights.

While another lab eventually offered to let us borrow their Sutter P-97, this one helped us get started. It isn't perfect—frankly, it's hacky as hell—but it works in a pinch.

Principles

For starters, the kind of pipette I'm talking about—the kind we needed—is formed from glass microcapillary tubing, and has an open tip of 5–10 um in diameter that is plugged with a bit of agarose (if you aren't familiar, it behaves like gelatin). Our preferred tip-taper-length has not yet been determined, as we will do so through experimentation. If any of the above sounds familiar to you, these will be used for extracellular field-level recording rather than patch clamping.

Starting with a glass microcapillary of constant inner and outer diameter (much larger than the desired tip diameter) and clamping the microcapillary at both ends, a pipette puller must heat the center to soften the glass and pull the two ends apart, drawing the center to a thin taper. Either by the act of pulling itself, or using diamond-tipped cutting pen, the microcapillary is separated into two pipettes, at the center.

When pulling a pipette, you're typically trying to match a specified tip diameter, tip taper length, and tip taper angle, and depending on the pipette puller, you may be offered a number of variables to adjust while attempting to do so. Among these include soak (preheat) and pull temperatures, soak time, pull tension, velocity, and distance, and internal air pressure (if the puller allows for it)—a tangled web of interdependent variables.

Design

Pipette puller front (left) and back (right). All puller electronics powered by (and fit inside of) a cheap, used, lower power ATX computer power supply (PSU). Additional fan added to the top of the PSU to cool the FET for the nichrome wire heater. Front panel built atop wood from the lid of a wine box, adorned with the hackiest of tape labels.

The puller I designed consists of a stationary upper microcapillary clamp, a driven lower clamp (with upper and lower limit-switches), and a nichrome-wire heater in between.

At left and center: driven lower clamp carriage made, in part, from the laser sled mechanics of a CD-ROM drive and a larger motor. At right: microcapillary clamps made from long PCB standoffs (with holes driven through them transversely, through which the microcapillaries are passed) and computer case thumbscrews (which clamp down on the inserted microcapillaries). PCB standoffs are also used for mounting the coiled nichrome wire (heater), and are insulated from the heat using fiberglass disks (shown in other phots but not here)

To keep things simple, I opted to allow for the adjustment of only two variables, either setting the rest constant or allowing them to vary naturally in subservience to the rest. Those variables are soak temperature and pull temperature, and can be set using the two potentiometer knobs on the front panel.

Temperature adjustment knobs and heater indicator lights.

Upon powering up the device, the green READY LED is lit. After raising the lower clamp carriage to its highest position, the user inserts a glass microcapillary through the upper clamp, nichrome wire heater, and lower clamp, gently tightens both clamps, and presses the START button. In response:

  1. The red TEMP 1 indicator LED is lit, the heater is heated to the soak temperature (TEMP 1) for thirty seconds, and the pipette is pulled gently at TEMP 1 for one second.

  2. The TEMP 1 indicator is turned off, the red TEMP 2 indicator is lit, the heater is heated to the pull temperature for twenty seconds, and the pipette is pulled at TEMP 2 until the lower limit switch it hit.

    Note: Depending on the temperatures set (and to what degree they soften the glass), the first pull might stretch the microcapillary substantially or not at all, and the second pull might stretch it immediately or after some delay, in both cases limited by torque of the small motor used.

  3. The TEMP 2 indicator and heater are turned off, the cooling fan is run for thirty seconds and shut off, and all three indicators are flashed twice. Finally, the green READY LED is lit again.

Example of a pulled pipette.

Electronics and Code

The code is run on an Arduino Pro Mini clone, and flashed using Platformio.

Carrier board for Arduino Pro Mini (not mounted) with FET nichrome wire driver pictured on left; full bridge motor controller and fan driver pictured on right. Though the motor was only driven in one direction in the firmware, the capability to drive in both directions was maintained in hardware to allow for firmware updates that made use of it, if they became necessary.

platformio.ini

[env:pro16MHzatmega328]
platform = atmelavr
framework = arduino
board = pro16MHzatmega328

src/main.cpp

/*******************************************************************************
 *
 *     Thing:   Pipette puller driver
 *
 *    Author:   Garrett Goss
 *      Date:   Dec 31, 2015
 *
 *   License:   MIT, Copyright (c) 2015 Garrett Marshall Goss
 *
 ******************************************************************************/

##include "Arduino.h"

// inputs
##define POT_HEATER_1         A3
##define POT_HEATER_2         A2
##define BUTTON_LIMIT_TOP     14
##define BUTTON_LIMIT_BOTTOM  12
##define BUTTON_START          9 // timer1

// outputs
##define HEATER               10 // timer1
##define FAN                   2
##define MOTOR_FWD             5 // timer0 (along with delay and millis)
##define MOTOR_REV             6 // timer0
##define LED_HEATER_1         11 // timer2
##define LED_HEATER_2          4
##define LED_READY             8

// Flashes all LEDs a specified number of times
void indicate(int counter) {
  for (int i = 0; i < counter; i++) {
    digitalWrite(LED_READY, 1);
    digitalWrite(LED_HEATER_2, 1);
    digitalWrite(LED_HEATER_1, 1);
    delay(500);
    digitalWrite(LED_READY, 0);
    digitalWrite(LED_HEATER_2, 0);
    digitalWrite(LED_HEATER_1, 0);
    delay(500);
  }
}

// Does nothing until start button is pressed
void waitForStart() {
  while (digitalRead(BUTTON_START)) {
  }
}

// Returns (0) if either a limit switch or the start button is hit. 
// Listening for the start button allows for the pulling process to be
// interrupted by the user
bool limits() {
  bool top = digitalRead(BUTTON_LIMIT_TOP); // 0 if pressed
  bool bottom = digitalRead(BUTTON_LIMIT_BOTTOM); // 0 if pressed
  bool start = digitalRead(BUTTON_START); // 0 if pressed
  bool limHit = 0;
  if (top == 0 || bottom == 0 || start == 0) limHit = 1; // 1 if pressed
  return limHit;
}

// Pull carriage downward, indefinitely or for a specified amount of time
// (milliseconds), at a specified duty cycle
void downFor(int ms) {
  digitalWrite(MOTOR_REV, 0);
  digitalWrite(MOTOR_FWD, 1);
  delay(ms);
  digitalWrite(MOTOR_FWD, 0);
}

// Pulls carriage downward until a limit switch (or the start button) is hit
void down() {
  digitalWrite(MOTOR_REV, 0);
  digitalWrite(MOTOR_FWD, 1);
  bool limHit = 0;
  while (!limHit) {
    limHit = limits();
  }
  digitalWrite(MOTOR_FWD, 0);
}

// Heats the heater to either set temperature 1 (when heaterNumber == 1)
// or to set temperature 2 (when heaterNumber == 2) for a specified amount
// of time (milliseconds). Temperatures predicted from the specifications
// of the nichrome wire used, and (roughly) validated by IR thermometer.
void heat(int heaterNumber, int ms) {
  digitalWrite(FAN, 0);
  int temp = 0;
  if (heaterNumber == 1) {
    int pot1 = analogRead(POT_HEATER_1); // 10 bit
    temp = map(pot1,0,1023,0,255);
    analogWrite(HEATER, temp);
    delay(ms);
  } else if (heaterNumber == 2) {
    int pot2 = analogRead(POT_HEATER_2); // 10 bit
    temp = map(pot2,0,1023,0,255);
    analogWrite(HEATER, temp);
    delay(ms);
  }
}

// Runs the cooling fan for a specified amount of time (milliseconds)
void coolFor(int ms) {
  analogWrite(HEATER,0);
  digitalWrite(FAN, 1);
  delay(ms);
  digitalWrite(FAN,0);
}

void setup() {
  pinMode(POT_HEATER_1, INPUT);
  pinMode(POT_HEATER_2, INPUT);
  pinMode(BUTTON_LIMIT_TOP, INPUT_PULLUP);
  pinMode(BUTTON_LIMIT_BOTTOM, INPUT_PULLUP);
  pinMode(BUTTON_START, INPUT_PULLUP);
  pinMode(3, INPUT);
  pinMode(HEATER, OUTPUT);
  pinMode(FAN, OUTPUT);
  pinMode(MOTOR_REV, OUTPUT);
  pinMode(MOTOR_FWD, OUTPUT);
  pinMode(LED_HEATER_1, OUTPUT);
  pinMode(LED_HEATER_2, OUTPUT);
  pinMode(LED_READY, OUTPUT);
}

void loop() {
  // wait for start
  digitalWrite(LED_READY, 1);
  waitForStart();
  
  // heat to first temperature, pull small amount
  digitalWrite(LED_READY, 0);
  digitalWrite(LED_HEATER_1, 1);
  heat(1, 30000);
  downFor(1000);
  
  // heat to second temperature, pull until limit switch is hit
  digitalWrite(LED_HEATER_1, 0);
  digitalWrite(LED_HEATER_2, 1);
  heat(2, 20000);
  down();
  digitalWrite(LED_HEATER_2, 0);
  
  // cool down
  coolFor(30000);
  indicate(2);
}

To leave a comment below, sign in using Github.