Introduction: Atomic Force Microscope Model
A simple and cheap model of an Atomic Force Microscope. With 3D printable parts, and simple electronics. Suitable for every secondary school. Some stuff is in Dutch...
Supplies
Step 1: Print 3D Parts and Construct
Print all 3D parts. Used .4 nozzle and Prusament PLA.
construct using the m10 and m6 bolts and nuts and using double sided sticky tape.
Step 2: Connect Circuit
Step 3: Upload Arduino Code
Attachments
Step 4: Run Python Jupyter Notebook Code
import serial
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
import matplotlib.cm as cm
import time
# Seriële poortinstellingen
serial_port = '/dev/ttyACM0' # Pas dit aan naar de juiste poort
baud_rate = 9600
# Aantal datapunten om te plotten
max_data_points = 3000
# Lijsten om gegevens op te slaan
data = [] # data is recorded first in this array, and then split in the followin arrays:
x_data = []
y_data = []
voltage_data = []
# Maak een seriële verbinding
ser = serial.Serial(serial_port, baud_rate)
while True:
try:
ser.close()
time.sleep(1)
ser.open()
print("serial opened")
time.sleep(1)
print("serial started")
read=ser.readline()
#print(read.decode('utf-8'))
break # Exit this loop if start is successfull
except:
print("Failed to start or read serial. Retrying in 1 second...")
time.sleep(1) # Wait for 1 second before retrying
while True:
try:
if ser.in_waiting > 0:
line = ser.readline().decode().strip()
#print(line) #this show all incoming data
if line:
data.append(line)
if len(data) >= max_data_points: # Check if max. data points is recorded, then stop recording and plot
break
except UnicodeDecodeError:
continue
except Exception as e:
print(f"Exception occurred: {str(e)}")
break
ser.close() # Close the serial connection
print('Data collection completed.')
for line in data:
#range(max_data_points):
# Lees een regel van de seriële poort
#line = ser.readline().decode().strip()
# Split de regel in x, y en voltage waarden
values = line.split(',')
x = int(values[0].split(':')[1].strip())
y = int(values[1].split(':')[1].strip())
voltage = float(values[2].split(':')[1].strip())
# Voeg de waarden toe aan de lijsten
x_data.append(x)
y_data.append(y)
voltage_data.append(voltage)
# Filter data based on voltage
filtered_x_data = []
filtered_y_data = []
filtered_voltage_data = []
for i, voltage in enumerate(voltage_data):
if voltage >= 1: #change to set groundlevel / remove noise
filtered_x_data.append(x_data[i])
filtered_y_data.append(y_data[i])
filtered_voltage_data.append(voltage)
# Plot the filtered data
fig = plt.figure(figsize=(12,12))
ax = fig.add_subplot(111, projection='3d')
ax.scatter(filtered_x_data, filtered_y_data, filtered_voltage_data, c=filtered_voltage_data, cmap='hot_r')
# Set the axes labels
ax.set_xlabel('X')
ax.set_ylabel('Y')
ax.set_zlabel('Voltage')
# Set up the color bar
norm = plt.Normalize(min(filtered_voltage_data), max(filtered_voltage_data))
cbar = plt.colorbar(cm.ScalarMappable(norm=norm, cmap='hot_r'))
cbar.set_label('Voltage (V)')
# Set the axis limits
ax.set_xlim(min(filtered_x_data), max(filtered_x_data))
ax.set_ylim(min(filtered_y_data), max(filtered_y_data))
ax.set_zlim(1, max(filtered_voltage_data)) # Set the minimum voltage to 1V
# Display the plot
plt.show()









