../ --> Go back to Homepage

Conductivity Based Atomic Force Microscope v0.0.1

By: Vincent Banek --- Date: 3/8/25

(Original Report for college course: May 2024)

Notes: I originally made this project for my subsystems college course (CET4711) in spring 2024, This is my 2nd attempt of making an AFM, I also tried making one in high school but there was some misunderstandings about the arduino MCU, that caused it not to work well, this article is based on my project report for my college course, because of time constraints, I could not finish the upper half of the AFM, the upper half is for the probe that scans the item placed under it, to demonstrate its function, I hot glued a needle to a scrap plastic part to place the needle pointing down, I then needed to find a metal sample that would both fit the gap and produce a interesting image, even though I planned on some kind of film or semiconductor, I used a screw since its not that springy and the gap was to large for the type of item I actually wanted to scan.

Now that I graduated I plan on restarting the project, to function better and expand on it, for use on semiconductors, I also think that living cells could be interesting, after fixing the frame, my first modification planned is a optical microscope in order to see a image of the sample optically and via C-AFM, side by side, and see if the oscillation is correct.

I plan on releasing the code and CAD files on github but want to refactor the CAD files and rewrite the code for the Arduino Minima first to address some problems caused by the limited memory on the UNO.

Table of Contents


1Objectives

  1. Research Project
  2. Make a Conductivity based AFM (Atomic Force Microscope)
  3. Construct the rig that scans the object
  4. Create Code for it, and Wire it.
  5. Generate Image of the area scaned
  6. prove components work together and are useful.

2Component List

  1. Arduino Mega.
  2. 2 10kΩ Resistor
  3. 1 47uF Capicitor, One 1000uF one
    (1000uF is all I had, but it worked enough, under 47uF is to small)
  4. 10 47mm Piezo Disc (Marketed for Hybrid Acoustic Guitar Pickups)
    Used to make 3 actuators
    One is actually used as a conductive platform and isn’t active.
  5. wires and breadboard, solder and phototype board to expand and anchor wires.
  6. a needle to be used as probe
  7. Hot glue and hot glue gun
  8. 10 30mm M3 Screws, with 10 M3 nuts, and 20 M3 Washers
  9. A spring to put platform on so it can move freely, I used 7X12 5mm compressing spring.
  10. 3D printer for 3D printing parts
  11. 5V from USB.
  12. Computer with Arduino IDE, and to run the image program on Processing
  13. A condutive item to scan, I choose the thread of a small screw.


3 Choosing Project/Research

I have did this project before with less experience, with a similar setup but made of cardboard and without knowing the difference between PWM and real Analog Voltage, assuming it was already analog voltage, I got patterns of dots, but could not understand it, I built it because I became obsessed with microtechnology and saw a video of IBM making cartoons with molocules with a version, that can both see and make things,
There version is way to complex for me to build,
I can get started by making a very simple one, its very common to use piezoelectric actuators instead of normal motors, ones made for other applications like guitar pickups, or speakers, can be modified for this application,
Theres one here using it:
The one above uses a custom laser setup made from a CD-ROM, but since I am instrusted in electronics and looking at metals, I can simplify it even more by making a conducivity based one, and using a needle and conductive platform to get the conducvity creating a microscopic map/image of conductivity.
This can be useful for looking at the quality of metal like microscopic cracks, or to see the conductivity of semiconductors, it may be possible to connect one pin at a time and get several images, of what each pin connects to, unfortently most chips have epoxy and other coatings thats hard to remove without destroying the component. Because doing this correctly would be to time consuming I will be just imaging a thread of a screw, which can be used to see thats there a edge, and if quality is high enough to see if there is any cracks.


4Procedure

4.1Part 1: Designing and building the rig:

My final phototype is based on this:
figure photos/drawing0.png
I used a combination of hand made drawings and Freecad to design the Rig,
figure photos/freecad2.png
To be honest I was running out of time so instead of redesigning for the decision to connect all of the actuators to the platform, which I originally planned on being on the probe, I just drilled holes to fit the actuators the way on the picture, onto the base in the freecad design., it formed a partial box, so instead of making a holder for the probe, I just took a spare plastic part and glued it on time, and glued the needle to it, after placing the object to be scanned, unfortentently because its glued its fixed for the expirement with the screw.


Each actuator is made out of 3 piezo disk
figure photos/rig2.png
They are then wired in parallel.
At the end the machine looks like this:
figure photos/Rig0.png

4.2Part 2: Writing Code for it:

I wrote the code mostly surrounding 2 for loops for X and Y, to create the 2D image.

void ProbeCord(char movx, char movy) {
  // had to make the code downscale by a quarter for it to fit on arduino.
  int qmovx = movx*4;
  int qmovy = movy*4;
  
  moveprobe(qmovx, qmovy, 255);
  char qnn = constrain(map(analogRead(probe), lower, upper, 0, 255), 0, 255);
  moveprobe(qmovx+1, qmovy, 255);
  char qpn = constrain(map(analogRead(probe), lower, upper, 0, 255), 0, 255);
  moveprobe(qmovx, qmovy+1, 255);
  char qnp = constrain(map(analogRead(probe), lower, upper, 0, 255), 0, 255);
  moveprobe(qmovx+1, qmovy+1, 255);
  char qpp = constrain(map(analogRead(probe), lower, upper, 0, 255), 0, 255);
  ImageBuffer0[movx][movy] = (qnn+qpn+qnp+qpp)/4;
  digitalWrite(Zenable, LOW);
  digitalWrite(XYenable, LOW);
}
void TakeImage() {
  for(int yscan=0; yscan < 64; yscan++) {
    for(int xscan=0; xscan < 64; xscan++) {
      ProbeCord(xscan, yscan);
    }
    analogWrite(piezoX, 0);
    delay(RCDelay); // Give time for voltage to go down.
  }
}
I created the code above to scan the object, In TakeImage() it uses a for a for loop for y to go back to front and then within that for loop theres another one for x to go left to right that runs quicker, they fill the buffer made from a 2D char matrix 64x64, I would use int but it would be to big, and the resoultions already low. The Processing code is like this but backwards.
In order to include more data without using more memory I split each point into quadrants and scan 4 segments in a square, and sum them up, to get data from a total of 256x256 points, unfortently because this process downscales it back down to 64x64 it still loses detail, but I think its better then not including the data.

4.3Part 2: Wiring it:

I explain this in detail in the diagrams section.
But when wiring the piezo motors I needed to solder each array together in parrelel and hot glue the photoboard to the 3dprinted base since the wires where delicate. 2 of them snaped off, one I repaired, and another I used as the platform instead. Just for the metal surface so its important to anchor or tie down the wires for something like this, this is true for the probe too, which I hot glued the wire down for.

4.4Part 3: Place object and Calibrate Machine

In order to make the first image I needed a object to scan, I choose a small screw with a fine thread because its conductive and thought it would look interesting when imaged,
This was done by glueing one side down, while making sure the other side hit the metal surface, I then glued the needle on the piece of plastic above so it hit the screw.
figure photos/Rig0.png
unfortently it was mostly white because it was too close, moving it did not make better images, everything seemed to be working. the values did seem to vary but stayed aroud 130, there did seem to be a line, when looking at the numbers. so I added code to define lower and higher, and set it from 100 to 175.


4.5Part 4: Getting Image:

After running my processing program with the AFM connected,
I then got this image! :
figure photos/image0.png
I think its the thread or edge of the screw because of the lines, there was some glue on it I could not get off maybe thats the dots.


5Diagrams

5.1 Hardware: (Schematic Diagram)

figure photos/electrical-schematic.png
This is the schematic diagram of the project, the probe is connected directly to A0, 5V is connected to the metal platform.
1 of the piezo actuators made up of 3 piezo disk in parallel are connected directly between D11 and ground I used this instead of a driver conneted to pin 7 because I dont need PWM since its always 255, and switched rapidly on and off when needed via Zenable, I left the code there because I may change it later if I need depth detection, for now its just a 2D image,
The actuators starting with X and Y are grounded via a NPN transistor, controlled by pin 10, XYenable, this allows the RC circuit to charge to a certain voltage before the piezo disk moves, using the RC circuit alone would not work good because the Piezo disk have a certain frequency response, so while the rc circuit slowly brings the voltage up and down, the transistors rapidly switch on and off to put them on and back off, I designed the RC circuits though expirementation and guesing, and a suggestion I found on stackoverflow. I needed far bigger caps then what was mentioned though,


5.2 Hardware: (Picture of Electrical Circuit)

figure photos/circuit0.jpg
In the diagram above you can see a reflection of the schematic above I color coded the wires on the bottom, the black ones are ground, the Green one is X, The Red one is Y, and the Blue one, connected directly to the arduino is Z.
The yellow aligator clip is A0 for the probe, and the white aligator clip, is 5V for the metal platform. I used the red VCC rail as the XYenable instead if power connected to the Arduno with a orange wire.
figure photos/Rig0.png
The one on the bottom is Z with the blue wire, The one on the Left is X with the Green Wire, The one in the back is Y with the Red wire. the platform is a inactive piezo disk upsidedown connected to Z via a spring. and connected to the others with a plastic stick hot glued together. Theres a screw to image sitting on it.


Sub-Systems Used:

Following sub-systems of a computer-controlled system
are involved in this lab exercise:
Data Input Sub-system(s):
A needle as a probe connected directly to pin A0,
with the platform connected to 5V.
Data Processing and Data Storage Sub-systems:
Data Output Sub-systems(s):
3 Piezo based linear actuators, drived by 2 transistor activated RC Circuits.
Data Communication Sub-systems:


Diagrams and pictures (cont.):
figure photos/block-diagram.png

6 Source Code

<AFM-ArduinoCode.ino> - Arduino C Code, for AFM Machine.

char ImageBuffer0[64][64];
#define piezoX 3 // For X axis
#define piezoY 5 // For Y axis
#define piezoZ 7 // Not used if 255 only
// May be expanded for depth later
#define XYenable  10
#define Zenable   11 // Connect Piezo Z directly here
// it stays at 255 or 5V so this allows me make
// the circuit simpler
#define probe     A0
// Rewrite this during your calibration process. leave * 4, I prefer to use
// 0 to 255 but did not went to change code for 255, so left it like this.
int upper = 175 * 4; // Sets higher expected value, default is 255.
int lower = 100 * 4; // Sets lower expected value, default is 0.
// sets delay in ms to allow RC filter to charge.
int RCDelay = 10;
void setup() {
  // init serial
  Serial.begin(115200);
  // initialize digital pin LED_BUILTIN as an output.
  pinMode(LED_BUILTIN, OUTPUT);
  pinMode(piezoX, OUTPUT);
  pinMode(piezoY, OUTPUT);
  pinMode(piezoZ, OUTPUT);
  pinMode(XYenable, OUTPUT);
  pinMode(Zenable, OUTPUT);
  pinMode(probe, INPUT);
}
int GetValue(int getx, int gety){
    return ImageBuffer0[getx][gety];
}
void SendViaSerial() {
  Serial.print("."); // Signals new image.
  for(int ysend=0; ysend < 64; ysend++) {
    Serial.print(GetValue(0, ysend));
    for(int xsend=1; xsend < 63; xsend++) {
      Serial.print(GetValue(xsend, ysend));
      Serial.print(","); // next value
    }
    // next row
    Serial.println(GetValue(64, ysend));
  }
  Serial.print(";"); // to tell the system its done.
}
void moveprobe(char movx, char movy, char movz) {
  digitalWrite(Zenable, LOW);
  digitalWrite(XYenable, LOW); // Wait until cords are set.
  analogWrite(piezoX, movx); // go to cords
  analogWrite(piezoY, movy);
  analogWrite(piezoZ, movz);
  delay(1); // allow rc filter to get to right voltage.
  digitalWrite(XYenable, HIGH);
  delay(1); // very short delay, so probe does not scratch.
  digitalWrite(Zenable, HIGH);
}
void ProbeCord(char movx, char movy) {
  // had to make the code downscale by a quarter for it to fit on arduino.
  int qmovx = movx*4;
  int qmovy = movy*4;
  
  moveprobe(qmovx, qmovy, 255);
  char qnn = constrain(map(analogRead(probe), lower, upper, 0, 255), 0, 255);
  moveprobe(qmovx+1, qmovy, 255);
  char qpn = constrain(map(analogRead(probe), lower, upper, 0, 255), 0, 255);
  moveprobe(qmovx, qmovy+1, 255);
  char qnp = constrain(map(analogRead(probe), lower, upper, 0, 255), 0, 255);
  moveprobe(qmovx+1, qmovy+1, 255);
  char qpp = constrain(map(analogRead(probe), lower, upper, 0, 255), 0, 255);
  ImageBuffer0[movx][movy] = (qnn+qpn+qnp+qpp)/4;
  digitalWrite(Zenable, LOW);
  digitalWrite(XYenable, LOW);
}
void TakeImage() {
  for(int yscan=0; yscan < 64; yscan++) {
    for(int xscan=0; xscan < 64; xscan++) {
      ProbeCord(xscan, yscan);
    }
    analogWrite(piezoX, 0);
    delay(RCDelay); // Give time for voltage to go down.
  }
}
// the loop function runs over and over again forever
void loop() {
  digitalWrite(LED_BUILTIN, HIGH);  // show that program starts.
 
  TakeImage(); // Take the Atomic Force Image
  // send over serial
  
  SendViaSerial();
  digitalWrite(LED_BUILTIN, LOW); // To show speed of program
  delay(1500); // wait a while before next image.
}
<AFMProcessing.pde> - Processing Code for Image.

import processing.serial.*;
Serial myPort;  // Create object from Serial class
int val;      // Data received from the serial port
String SerialMsg;
void setup() 
{
  // 64 by 64 resolution scaled up by 10.
  size(640, 640);
  // Assumes 1st Serial Port
  String portName = Serial.list()[0];
  myPort = new Serial(this, portName, 115200);
  myPort.bufferUntil(’;’);
}
void draw()
{
  String[] rows = new String[65];
  String[] columns = new String[65];  
  if (SerialMsg != null) {
   rows = split(SerialMsg, ’\n’);
    for(int i=0; i<rows.length; i++) { 
     columns = split(rows[i], ’,’);
     for(int j=0; j < columns.length; j++) {
       fill(int(columns[j]));
       rect(j*10, i*10, 10, 10);
      }
    }
    SerialMsg = null;
  }
}
void serialEvent(Serial myPort) {
  SerialMsg = myPort.readStringUntil(’;’);
}

7Measurements

8Troubleshooting

I needed to change from a 256x256 int matrix to char matrix then had to settle for a 64x64 char matrix because of memory problems, I compromised by taking a bigger images and downscaling to include all the data. I also had trubble in the processing program, that it displayed nothing, it was solved when I removed the code setting the background that seemed to also blank it.

9Discussion

9.1Data Input Sub-Systems:


9.2Data Processing/Data Storage Subsystems:


9.3Data Output Sub-systems:


9.4Data Communications Subsystems:

9.5Hardware:

10Conclusion

This was a very interesting and educational project, while it may have not have been the smartest move to pick something that requried so many custom parts due to the time it took, it is still great because of the usefulness and the way it can be built on. I plan on continueing research on AFM and other nanotechnology. Specifically projects that can be done at home without fancy expensive machines or chemicals, because I believe its the next step for technology.
I am glad I got a interesting Image at the end of this expirement.
Some improvements I would make besides a better microcontroller and software would be a sound proof box or less noisy design, because it was to loud when running almost giving me ringing after the last time meaning that I cant really use it again without hearing protection or other improvements also I may add a normal microscope to see how it actually moves, I wanted to do this but ran out of time, after this I may see how it works on semiconductors.