Идея создания электронного курвиметра возникла в процессе разработки инструментальной выверки вращающейся печи. Для точного измерения диаметров опорных роликов и определения их износа необходимо было создать специальный прибор.
Износ роликов, возникающий в результате неправильной работы печи, требует ремонта, который заключается в шлифовке и выравнивании их профиля.

Курвиметр — это устройство, предназначенное для измерения длины извилистых линий на топографических картах, планах и чертежах. Основная идея заключалась в том, чтобы преобразовать показания энкодера в линейное расстояние.
Энкодер - представляет собой датчик угла поворота, который может быть нескольких типов: инкрементальный, абсолютный, оптический, магнитный и механический. Для своего проекта я выбрал 14-битный магнитный энкодер MT6701.

Контролёр, ответственный за обработку данных, выбрал ESP32, который уже был в наличии, и запрограммировал его на языке Micropython, в котором я немного разбираюсь. Затем подключил дисплей и энкодер, используя протокол I2C.
Чтобы точно определить диаметр измеряемого объекта, будь то ролик, колесо или что-то другое, необходимо знать, где начинается и заканчивается его оборот. Для этого нужен триггер — устройство, которое будет указывать на начало и конец вращения.
В качестве триггера я решил использовать геркон, но потом передумал из-за его особенностей: он может срабатывать дважды при прохождении магнита, а его чувствительность варьируется. К счастью, мне повезло, и я смог найти промышленный магнитный датчик, который отлично подошёл на роль триггера.
Алгоритм описание работы - при повороте энкодера все его углы необходимо складывать или отнимать в зависимости от направления вращения зная диаметр колеса энкодера, эти значения можно перевести в пройденный путь. Триггер делит этот путь отмеряя длину измеряемого ролика зная длину ролика получаем диаметр. Для качественного результата первым делом необходимо убрать первое измерение так-как оно меньше диаметра колеса, поскольку начинается не от начала триггера.
Далее проводим дополнительно несколько измерений с целью усреднения результата. В моём случае получилось добиться точности в десятые миллиметра.
Теоретическая точность получилось:
· 14bit = 2^14 = 16384
· при, D = 110 мм, L= π × D = 345,575 мм
· Расчетная теоретическая точность за импульс = D/16384 = 345,575/16384 = 0,02 мм.
Для вывода информации нашелся дисплей LCD1602 от старого проекта, который был успешно интегрирован в данное устройство.
В качестве источника питания применил аккумулятор 18650 + модуль заряда.
Схему подключения приводить не буду.
Код выглядит примерно так (это один из вариантов, отлаженный код в контроллере):
import machine
from time import sleep_ms
import math
from machine import Pin, ADC
from i2c_lcd1602 import I2C_LCD1602
i2c = machine.I2C(1,sda=machine.Pin(6), scl=machine.Pin(7), freq=400000)
LCD = I2C_LCD1602(i2c)
napr = 0 # Направление вращения 0 против часовой стрелки 1 по часовой
diameter = 110 # Диаметр колеса, мм
alfa_sum = 0
dtt = [] # Предыдущее значение
cz = [] # Счетчик оборотов по часовой стрелки
ct = [] # Счетчик оборотов по часовой стрелки
data_0 = []
booll=0
booll_per=[]
LCD.puts("Hello")
LCD.puts("kurva ", 2, 1)
sleep_ms(1000)
response=i2c.readfrom_mem(0x06, 3, 2) # Подключаемся к датчику
potentiometr = machine.ADC(28) # Подключаем аналоговый Pin (0)
potentiometr_value = potentiometr.read_u16()
str_return_data = str(response.hex()) # Подключаемся к датчику
feedback_data = int(str_return_data, 16) # Преобжаем в 10 ричной код
x = feedback_data/4 # Убираем лишние цифры
for dat in x:
data = dat
if 0 <= data <= 4096:
dt = 0
if 4096 <= data <= 8192:
dt = 1
if 8192 <= data <= 12288:
dt = 2
if 12288 <= data <= 16384:
dt = 3
dtt.append(dt) # Предыдущее значение записываем в массив
data_0.append(data)
if len(dtt)>=3: # Если массив меньше 2-х начинаем работу
dt_t = int(dtt.pop(-3)) # Предыдущее значение извлекаем из массива
if dtt[0] == 0 and dtt[1] == 3: # Ищем переход по часовой стрелки
cz.append(1) # Если есть переход записываем в массив
if dtt[0] == 3 and dtt[1] == 0: # Ищем переход по часовой стрелки
ct.append(3) # Если есть переход записываем в массив
data_1 = int(data_0.pop(-2)) # Предыдущее значение извлекаем из массива
if data != data_1:
alfa = float(data-data_1)
alfa_sum += alfa
dz = int(len(cz)*16384)
dt = int(len(ct)*16384)
alfa_real = round((360/(16384)*(alfa_sum+dt-dz)),2)
l_max = round(((math.pi*diameter)/360)*alfa_real,3)
d_nom = round(l_max/math.pi,1)
LCD.puts("%s: %s"% (round(alfa_real,1), round(l_max,1)))
if potentiometr_value >8000:
booll=1
if potentiometr_value <8000:
booll=0
booll_per.append(booll)
if len(booll_per)>2:
dt_booll_per = int(booll_per.pop(-2))
if booll == 0 and int(dt_booll_per) == 1:
alfa_sum = int(0)
cz = [0,0]
ct = [0,0]
LCD.clear()
LCD.puts(0.000)
LCD.puts("D=%s - mm" % abs(d_nom), 0, 1)
sleep_ms(50)
Дальше последовала разработка и печать корпуса.



Готовый проект выглядит так.
Всем спасибо на оригинальность не претендую. В проекте много чего можно изменить (доработать). Например переписать код на С провести оптимизацию.
P.S. проект по прямому назначению так и не пригодился.