
Современные робототехнические системы, дроны и автоматизированные устройства требуют точного определения перемещения в пространстве. Один из ключевых компонентов для этой задачи — Оптический модуль инерциальной навигации, такой как MTF02. Этот компактный и энергоэффективный сенсор позволяет устройствам "чувствовать" движение даже без GPS или внешних ориентиров.

В конструкции датчика MTF-02 интегрированы две ключевые подсистемы:
ToF motion sensor (Time-of-Flight) для получения точечного расстояния;
Сенсор оптического потока (Optical flow) для отслеживания движения поверхности.
Основные характеристики
Напряжение питания:4 - 5.5В, потребление ~200мВт;
Размеры/вес: ~25x10x4,5мм 1,5г;
Оптический поток: 42° - при освещенности 60 ≥ Lux;
Минимальная высота: ≥ 8см;
Максимальная скорость: до 7м/c на высоте 1 метр;
ToF motion sensor: до 2,5 м @ 90% отражения и 600 Lux, мертвая зона ToF-камеры после 2см;
Длина волны ToF: 940нм.
Процесс работы MTF-02:
ToF motion sensor — технология измерения расстояния до объекта с помощью времени задержки отраженного сигнала (лазерного или ИК-импульса). Точечные датчики измеряют дистанцию до одной точки.
Оптический поток (Optical flow) - датчик захватывает изображение поверхности вниз и вычисляет относительное движение при частоте ~50 Гц, работает начиная с высоты 8см и далее для алгоритмов стабилизации движения при полете или перемещении в помещении.
Это похоже на то, как компьютерная мышь определяет свое перемещение, но с более высокой точностью.
Интерфейсы и протоколы
UART, LVTL 3.3В;
поддерживаемые протоколы: Micolink, Mavlink (APM +PX4), MSP(iNav):
Частота передачи: 50 Гц.
Применение:
Дроны и квадрокоптеры
Стабилизация в помещении без GPS;
Точное позиционирование при посадке.
Роботы-пылесосы
Построение карты помещения;
Контроль пройденного пути.
Мобильная робототехника
Навигация автономных роботов;
Избегание столкновений.
Локализация и колижионирование
интеграция оптического потока и ToF
Аналитика движения
определение скорости движения по поверхности
Мое личное применение:
Задача стоит следующая: мне необходимо разработать такую систему, которая способна сканировать в пространстве над поверхностью т.е. по "воздуху".
Для решения поставленной задачи, был выбран датчик MTF-02, обладающий необходимыми характеристиками для одновременного определения пройденного пути, координат перемещения в плоскости (X, Y) и оценки высоты объекта.
Благодаря встроенномуToF motion sensor, обеспечивающей точное измерение расстояния, а также модулю оптического потока, MTF-02 способен адаптироваться к условиям, когда отсутствует прямая опора или контрольный фон, это делает его особенно эффективным в задачах, где важно отслеживать перемещение объекта в подвешенном состоянии или при движении над неровной/неоднородной поверхностью.
Схема подключения датчика MTF-02

Для более стабильного напряжения питания можно использовать следующую схему, в которой работает понижающий преобразователь MP231, но необходим источник +12В, в моем случае используется аккумуляторная сборка (NiMH/Pb +12В).
![Понижающий преобразователь напряжения [ +12V до +5V ] Понижающий преобразователь напряжения [ +12V до +5V ]](https://habrastorage.org/r/w780/getpro/habr/upload_files/77a/757/e95/77a757e95a91594c5aa260a8e0bc5349.png)
Вид осциллограммы передаваемых данных модуля MTF-02 по интерфейсу USART (линия TX)

Настройка микроконтроллера STM32F103 в CubeIDE

В пункте [ 1 ] настраиваю скорость (Baud Rate [115200]), остальные параметры без изменений;
-
В пункте [ 2 ] заходим в параметр "DMA Settings" и включаем его на примем данных;
В рамках реализации приема данных по интерфейсу(USART) была задействована технология прямого доступа к данным (DMA), что позволило существенно снизить нагрузку на центральный процессор.
Для этого приемный сигнал USART(USART_RX) был сконфигурирован на работу в режиме DMA, при котором поступающие данные автоматически записываются в выделенный участок оперативной памяти без участия ядра.
• В пункте [ 3 ] заходим в параметр "NVIC Settings" и включаем глобальное прерывание.
Для отслеживания состояния интерфейса USART и обработки важных событий (например, завершения приема или ошибки), в разделе NVIC Settings было включено глобальное прерывание USART, это обеспечивает возможность немедленного реагирования со стороны микроконтроллера на изменения состояния периферии без постоянного опроса регистров.
Реализация программного кода(настройка и прием данных)
Создание переменных и макросов
extern volatile uint8_t uartRxFullIRDone; //сработало прерывание по полному буферу
extern volatile uint8_t uartRxHalfIRDone; //сработало прерывание по половине буфера
extern short status_UART;
#define UART_RX_BUFFER_SIZE 96//основной буфер
uint8_t uart_rx_buffer_MTF[UART_RX_BUFFER_SIZE]={0,};
uint8_t uart_rx_buffer_MTF_copy[UART_RX_BUFFER_SIZE]={0,};
#define SIZEBUF_uart_rx_buf_mtf 64 //128 16
unsigned char uart_rx_buf_mtf[SIZEBUF_uart_rx_buf_mtf]={0,};
int size_uart_rx_buf_mtf=0;
MICOLINK_MSG_t msg;
MICOLINK_PAYLOAD_RANGE_SENSOR_t payload;
//буфер для сборки строки
#define SIZEBUF_result 96
char uart_rezult_buf1[SIZEBUF_result]={0,};
char uart_rezult_buf2[SIZEBUF_result]={0,};
char* uart_rezult_buf=uart_rezult_buf1;
short uart_rezult_buf_i=0;//индекс
char* uart_bufRow=uart_rezult_buf1;//буфер с целой строкой
//E N D буфер для сборки строки
//E N D для составления строк
//Данные полученные от структуры
float distance_m=0.0f;
int16_t flow_vel_x_cop=0;
float flow_vel_x_cop_ab=0.0f;
int16_t flow_vel_y_cop=0;
float flow_vel_y_cop_ab=0.0f;
uint32_t time_ms_s = 0;
float distance_global =0.0f;
//E N D данные полученные от структуры
//Данные после преобраз.сглаживания
float smoothed_x = 0.0f; // Сглаженная скорость по X (см/с)
float smoothed_y = 0.0f; // Сглаженная скорость по Y (см/с)
float smoothed_distance = 0.0f; // Сглаженная дистанция (м)
float total_velocity = 0.0f; // Общая скорость из сглаж. линейных скор. и дистанции (см/с)
//E N D Данные после преобраз.сглаживания
static float total_path_m = 0.0f; // Пройденный путь (метры)
float total_path_m_cop = 0.0f;
long total_path_m_cop_long =0; //тест
static float position_x_m = 0.0f; // Положение по X (в метрах)
float position_x_m_cop = 0.0f;
long position_x_m_cop_long= 0;
static float position_y_m = 0.0f; // Положение по Y (в метрах)
float position_y_m_cop = 0.0f;
long position_y_m_cop_long= 0;
float beta_rad = 0.0f;
// Буферы для сглаживания данных
#define BUFFER_SIZE 5 // Размер буфера для сглаживания, если необходимо еще медленее, уменьшать размер
float flow_vel_x_buffer[BUFFER_SIZE] = {0}; // Буфер для flow_vel_x
float flow_vel_y_buffer[BUFFER_SIZE] = {0}; // Буфер для flow_vel_y
float distance_buffer[BUFFER_SIZE] = {0}; // Буфер для дистанции
uint8_t buffer_index = 0; // Индекс текущего положения в буфере
// E N D Буферы для сглаживания данных
Структуры MICOLINK_MSG_t msg и MICOLINK_PAYLOAD_RANGE_SENSOR_t
Реализацию структур я взял с официального сайта [ https://micoair.com/docs/decoding-micolink-messages-from-mtf-01/ ]
#define MICOLINK_MSG_HEAD 0xEF
#define MICOLINK_MAX_PAYLOAD_LEN 64
#define MICOLINK_MAX_LEN MICOLINK_MAX_PAYLOAD_LEN + 7
enum
{
MICOLINK_MSG_ID_RANGE_SENSOR = 0x51, // Range Sensor
};
/*
Message Structure Definition
*/
typedef struct
{
uint8_t head;
uint8_t dev_id;
uint8_t sys_id;
uint8_t msg_id;
uint8_t seq;
uint8_t len;
uint8_t payload[MICOLINK_MAX_PAYLOAD_LEN];
uint8_t checksum;
uint8_t status;
uint8_t payload_cnt;
} MICOLINK_MSG_t;
// Range Sensor
typedef struct
{
uint32_t time_ms; // System time in ms
uint32_t distance; // distance(mm), 0 Indicates unavailable
uint8_t strength; // signal strength
uint8_t precision; // distance precision
uint8_t dis_status; // distance status
uint8_t reserved1; // reserved
int16_t flow_vel_x; // optical flow velocity in x
int16_t flow_vel_y; // optical flow velocity in y
uint8_t flow_quality; // optical flow quality
uint8_t flow_status; // optical flow status
uint16_t reserved2; // reserved
} MICOLINK_PAYLOAD_RANGE_SENSOR_t;
Метод uart_Handler_MTF
Данный метод отвечает за получение, предварительную обработку и подготовку к использованию данных, поступающих от датчика MTF-02.
Основные задачи метода
• Приём данных с датчика
Метод реагирует на прерывания DMA — по заполнению первой или второй половины приёмного буфера. Это позволяет работать с потоком данных непрерывно, без потерь.
• Буферизация и переключение кадров
Используются два чередующихся буфера (uart_rezult_buf1 и uart_rezult_buf2), чтобы приём новых данных и обработка предыдущих шли параллельно.
• Декодирование пакета
Полученные байты передаются в функцию micolink_decode, которая разбирает пакет и выделяет физические величины:
flow_vel_x_cop — линейная скорость по оси X
flow_vel_y_cop — линейная скорость по оси Y
distance_m — дистанция до поверхности
• Сглаживание данных
Для уменьшения шумов значения проходят через циклический буфер и усредняются функцией calculate_average. Это даёт стабильные показания скорости и расстояния.
• Интегрирование скорости в путь
На основе сглаженных скоростей выполняется интегрирование (update_position) для получения пройденного пути по осям X и Y.
Параллельно рассчитывается общая длина пути и угол движения (calculateBetaRadians).
• Подготовка данных для передачи
Формируются готовые строки (sprintf) с данными в удобном текстовом формате для отладки, логирования или передачи в другие системы.
void uart_Handler_MTF(void)
{
HAL_Delay(1);//чтобы HAL_GetTick() не выдавал ноль
uint32_t ms = HAL_GetTick();
// uint32_t time_sec = ms / 1000;
char isData=0;
char* pData=(char*)uart_rx_buffer_MTF;
if(uartRxFullIRDone){
uartRxFullIRDone = 0;
// Указатель на вторую половину основного буфера DMA
pData=(char*)&uart_rx_buffer_MTF[UART_RX_BUFFER_SIZE/2];
isData=1;
}
if(uartRxHalfIRDone){
uartRxHalfIRDone = 0;
// Указатель на первую половину основного буфера DMA
pData = (char*)uart_rx_buffer_MTF;
isData=1;
}
if(isData)
{
isData=0;
if(uart_rezult_buf==uart_rezult_buf1){
memcpy(uart_rezult_buf1, pData, UART_RX_BUFFER_SIZE / 2);
uart_bufRow=uart_rezult_buf1;
uart_rezult_buf=uart_rezult_buf2;
}else{
memcpy(uart_rezult_buf2, pData, UART_RX_BUFFER_SIZE / 2);
uart_bufRow=uart_rezult_buf2;
uart_rezult_buf=uart_rezult_buf1;
}
memcpy(uart_rx_buffer_MTF_copy,(uint8_t*)uart_bufRow,UART_RX_BUFFER_SIZE);
micolink_decode(uart_rx_buffer_MTF_copy,UART_RX_BUFFER_SIZE);
//Сглаженные значения
flow_vel_x_buffer[buffer_index] = flow_vel_x_cop;
flow_vel_y_buffer[buffer_index] = flow_vel_y_cop;
distance_buffer[buffer_index] = distance_m;
buffer_index = (buffer_index + 1) % BUFFER_SIZE; // Циклический буфер
// Рассчитываем сглаженные значения
smoothed_x = calculate_average(flow_vel_x_buffer);
smoothed_y = calculate_average(flow_vel_y_buffer);
smoothed_distance = calculate_average(distance_buffer);
//E N D Сглаженные значения
float time_sec = ms/1000.0f;//перевод в секунды
update_position(smoothed_x,smoothed_y,ms);//интегрирование линейной скорости для расчёта пройденного пути, с учётом фильтрации малых шумов.
update_motion(smoothed_x,smoothed_y,smoothed_distance, ms);//расчёт общей скорости и пройденного пути
//делаю копию потому что position_x_m,y и total_path_m static (если одтать в буфер staic, то работать система не будет)
position_x_m_cop = position_x_m;
position_y_m_cop = position_y_m;
total_path_m_cop = total_path_m*1000.0f;
total_path_m_cop_long = (long)roundf(total_path_m_cop);
flow_vel_x_cop_ab=position_x_m_cop * 1000.0f;//перевод в мм
flow_vel_y_cop_ab=position_y_m_cop * 1000.0f;
position_x_m_cop_long = (long)roundf(flow_vel_x_cop_ab);
position_y_m_cop_long = (long)roundf(flow_vel_y_cop_ab);
//E N D
beta_rad = calculateBetaRadians(flow_vel_x_cop_ab, flow_vel_y_cop_ab);//получение угла в радианах
size_uart_rx_buf_mtf = sprintf((char*)&uart_rx_buf_mtf[0], "%ld %ld %.6f %ld %.3f %d %d>",
position_x_m_cop_long, position_y_m_cop_long,beta_rad, total_path_m_cop_long, time_sec, 1,0);//отправка пакета UART ведущему устройству
}
}
Метод update_motion
Данный метод отвечает за расчёт общей скорости и пройденного пути, он выполняет ключевую навигационную задачу — на основе данных от MTF-02 вычисляет, с какой скоростью движется объект и какое расстояние он прошёл с момента старта измерений.
Принцип работы
• Измерение времени между кадрами
Функция хранит момент предыдущего вызова (last_time_ms) и определяет, сколько секунд прошло между текущим и прошлым измерением (delta_time_s). Это позволяет интегрировать движение по времени.
• Вычисление мгновенной скорости
Используются проекции скорости по осям X и Y (flow_vel_x, flow_vel_y).
Их векторная сумма (sqrtf(...)) даёт модуль скорости в плоскости.
Результат умножается на измеренное датчиком расстояние до поверхности (distance_m), что учитывает масштаб оптического потока.
Деление на 100 применяется, если исходные скорости приходят в сантиметрах в секунду (приведение к м/с).
• Интегрирование для получения пути
Общая скорость умножается на интервал времени — это даёт приращение пути за данный шаг.
Приращение накапливается в переменной total_path_m, которая отражает суммарное пройденное расстояние с начала работы системы.
• Обновление времени
В конце функция сохраняет текущее время вызова, чтобы при следующем измерении корректно вычислить delta_time_s.
Простыми словами
Метод update_motion — это шагомер с точностью до миллиметров, но не по количеству шагов, а по точным данным от оптического датчика.
Он измеряет скорость движения, умножает её на прошедшее время и складывает результат в копилку пройденного пути
// Функция расчёта общей скорости и пройденного пути
void update_motion(float flow_vel_x, float flow_vel_y, float distance_m,uint32_t time_ms) {
static uint32_t last_time_ms = 0; // Время предыдущего измерения
float delta_time_s = (time_ms - last_time_ms) / 1000.0f; // Время в секундах
if (delta_time_s > 0) {
// Рассчитываем общую скорость (м/с)
float total_velocity_m_per_s =distance_m * sqrtf(flow_vel_x * flow_vel_x + flow_vel_y * flow_vel_y)/100.0f;// деление на 100 если скорости передаются в см/c если в м/то не надо делить
// Интегрируем скорость для расчёта пути
total_path_m += total_velocity_m_per_s * delta_time_s;
}
last_time_ms = time_ms; // Обновляем время последнего измерения
}
Метод update_position
Данный метод отвечает за то, чтобы перевести показания датчика MTF-02 из скоростей в координаты — то есть понять, где сейчас находится объект относительно точки старта.
Как это работает
Определение времени между измерениями
Метод вычисляет, сколько секунд прошло с момента предыдущего вызова (delta_time_s).
Это нужно, чтобы правильно учесть, на какое расстояние мог сдвинуться объект.
• Отсев шумов
Если скорость по X или Y слишком мала (меньше 0,01 см/с), она считается шумом и приравнивается к нулю. Это предотвращает накопление ошибок из-за микроколебаний или дрожания датчика.
• Перевод в метры в секунду
Показания датчика приходят в сантиметрах в секунду, поэтому они делятся на 100, чтобы работать в метрической системе (м/с).
Интегрирование — путь из скорости
Скорость умножается на время, прошедшее с предыдущего измерения.
Полученное приращение добавляется к текущим координатам position_x_m и position_y_m.
Таким образом, шаг за шагом накапливается точка текущего положения в метрах.
• Обновление времени
Сохраняется момент последнего измерения, чтобы при следующем вызове правильно рассчитать delta_time_s.
Простыми словами
update_position — это математический «следопыт»:
он берёт скорости, отбрасывает шум, переводит их в пройденное расстояние и складывает с предыдущими координатами.
В результате получается текущая позиция объекта в двухмерном пространстве.
//интегрирование линейной скорости для расчёта пройденного пути, с учётом фильтрации малых шумов.
void update_position(float flow_vel_x, float flow_vel_y,uint32_t time_ms){
static uint32_t last_time_ms = 0;// Время последнего измерения (мс)
// Вычисляем разницу во времени между измерениями в секундах
float delta_time_s = (time_ms - last_time_ms) / 1000.0f;
if (delta_time_s > 0.0f) {
// Проверка на малые скорости и шумы
if (fabsf(flow_vel_x) < 0.01f) flow_vel_x = 0.0f; // Игнорируем шум по X
if (fabsf(flow_vel_y) < 0.01f) flow_vel_y = 0.0f; // Игнорируем шум по Y
// Переводим скорости из см/с в м/с
float velocity_x_mps = flow_vel_x / 100.0f; // Линейная скорость по X (м/с)
float velocity_y_mps = flow_vel_y / 100.0f; // Линейная скорость по Y (м/с)
// Интегрируем скорости для обновления положенияx`
position_x_m += velocity_x_mps * delta_time_s; // Путь = Скорость * Время
position_y_m += velocity_y_mps * delta_time_s;
}
// Обновляем время последнего измерения
last_time_ms = time_ms;
}
Метод calculateBetaRadians перевод угла в радианы
float calculateBetaRadians(float flow_vel_x, float flow_vel_y)
{
return atan2(flow_vel_y, flow_vel_x); // Угол в радианах
}
Метод calculate_average вычисление среднего значения из буфера, необходи для сглаживания данных поступающих от датчика MTF-02
float calculate_average(float *buffer) {
float sum = 0.0;
for (int i = 0; i < BUFFER_SIZE; i++) {
sum += buffer[i];
}
return sum / BUFFER_SIZE;
}
//E N D функция вычисления среднего значения из буфера
Обработка и расшифровка данных MicoLinkВ
В работе с датчиком MTF-02 информация передаётся в виде бинарных сообщений по протоколу MicoLink. Этот набор функций выполняет полный цикл приёма — от поимки первого байта до получения готовых чисел скорости и высоты.
1. Метод micolink_parse_char, осуществляет приём и разбор данных, обрабатывает поток входящих байтов, поступающих от датчика.
Каждый байт проходит через «машину состояний»:
Заголовок — признак начала пакета.
ID устройства и системы — кому адресовано сообщение.
ID сообщения — тип передаваемых данных (например, показания дальномера).
Длина полезной нагрузки — сколько байт занимает полезная информация.
Полезная нагрузка — сами измеренные значения (скорости, дистанция).
Контрольная сумма — защита от ошибок в передаче.
Если всё прошло успешно и контрольная сумма совпала — пакет считается принятым.
2. Метод micolink_check_sum, осуществляет проверку целостности
Каждое сообщение содержит контрольную сумму — специальное число, рассчитанное по всем байтам пакета.
Если расчёт на приёмной стороне совпадает с переданным значением, значит, данные достоверны.
Этот шаг защищает от искажений, которые могут возникнуть в линии связи.
3. Метод micolink_decode, осуществляет декодирование,после успешного приёма пакет разбирается по смыслу.
В случае с MICO_LINK_MSG_ID_RANGE_SENSOR из него извлекаются:
time_ms — отметка времени измерения;
distance_m — высота над поверхностью, в метрах;
flow_vel_x и flow_vel_y — линейные скорости по осям X и Y (см/с).
Эти значения затем используются для расчёта скорости, перемещения и построения траектории движения.
// Функция обработки данных uint8_t* data, size_t size
void micolink_decode(uint8_t* data, size_t size)
{
//static MICOLINK_MSG_t msg;
if (micolink_parse_char(&msg,data,size) == false) {
return;
}
switch (msg.msg_id) {
case MICOLINK_MSG_ID_RANGE_SENSOR: {
//MICOLINK_PAYLOAD_RANGE_SENSOR_t payload;
memcpy(&payload, msg.payload, msg.len);
// Обработка данных датчика
uint32_t time_ms = payload.time_ms;
time_ms_s = time_ms;
uint32_t distance = payload.distance;
distance_m =(float)distance/1000.0f;//перевел мм в метры // высота
int16_t flow_vel_x = payload.flow_vel_x;
flow_vel_x_cop = (float)flow_vel_x;
int16_t flow_vel_y = payload.flow_vel_y;
flow_vel_y_cop = (float)flow_vel_y;
break;
}
default:
// Обработка других сообщений
break;
}
}
// Проверка контрольной суммы
bool micolink_check_sum(MICOLINK_MSG_t* msg) {
uint8_t length = msg->len + 6; // Длина сообщения
uint8_t temp[MICOLINK_MAX_LEN];
uint8_t checksum = 0;
memcpy(temp, msg, length);
for (uint8_t i = 0; i < length; i++) {
checksum += temp[i];
}
return (checksum == msg->checksum);
}
// Парсинг входящего байта
bool micolink_parse_char(MICOLINK_MSG_t* msg, uint8_t* data, size_t size) {//uint8_t data
for (size_t i = 0; i < size; i++) {
uint8_t byte = data[i]; // Получаем очередной байт из буфера
switch (msg->status) {
case 0: // Ожидание заголовка
if (byte == MICOLINK_MSG_HEAD) {
msg->head = byte;
msg->status++;
}
break;
case 1: // ID устройства
msg->dev_id = byte;
msg->status++;
break;
case 2: // ID системы
msg->sys_id = byte;
msg->status++;
break;
case 3: // ID сообщения
msg->msg_id = byte;
msg->status++;
break;
case 4: // Номер последовательности
msg->seq = byte;
msg->status++;
break;
case 5: // Длина полезной нагрузки
msg->len = byte;
if (msg->len == 0) {
msg->status += 2;
} else if (msg->len > MICOLINK_MAX_PAYLOAD_LEN) {
msg->status = 0; // Сброс из-за ошибки
} else {
msg->status++;
}
break;
case 6: // Прием полезной нагрузки
msg->payload[msg->payload_cnt++] = byte;
if (msg->payload_cnt == msg->len) {
msg->payload_cnt = 0;
msg->status++;
}
break;
case 7: // Контрольная сумма
msg->checksum = byte;
msg->status = 0; // Сброс статуса
if (micolink_check_sum(msg)) {
return true; // Сообщение успешно принято
}
break;
default:
msg->status = 0;
msg->payload_cnt = 0;
break;
}
}
return false;
}
Метод uart_startRecieving_MTF
После вызова данного метода MTF-02 начинает передавать пакеты данных по UART, а контроллер непрерывно принимает их в выделенный буфер, не тратя ресурсы на побайтовую обработку. Когда буфер наполняется наполовину или полностью, срабатывают соответствующие обработчики (uartRxHalfIRDone и uartRxFullIRDone), и начинается разбор протокола MicoLink.
void uart_startRecieving_MTF(void)
{
status_UART=1;//1=startRecieving 2=RxHalf 3=RxCplt
memset(uart_rx_buffer_MTF,0,sizeof(uart_rx_buffer_MTF));
HAL_UART_Receive_DMA(&huart2, (uint8_t*)uart_rx_buffer_MTF, UART_RX_BUFFER_SIZE);//начинаю прием данных от mtf_02 на uart2
}
Обработчики прерывания на прием
Данная реализация обработчиков конкретно у меня, находится в другом классе.
void HAL_UART_RxHalfCpltCallback(UART_HandleTypeDef *huart) //(перывание на прием от MTF)
{
if(huart == &huart2){//MTF_02
status_UART=2;//1=startRecieving 2=RxHalf 3=RxCplt //отладка
uartRxHalfIRDone = 1; //сработало прерывание по половине
}
}
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) //Callback от UART RX (перывание на прием от MTF)
{
if(huart == &huart2){//MTF_02
status_UART=3;//1=startRecieving 2=RxHalf 3=RxCplt //отладка
uartRxFullIRDone = 1; //сработало прерывание по полному буферу
}
}
Обработчик ошибок
void HAL_UART_ErrorCallback(UART_HandleTypeDef *huart)
{
if (huart->Instance == USART2 && enResetUART) { //MTF
/* Сброс ошибок и восстановление работы */
HAL_UART_DeInit(huart);
HAL_UART_Init(huart);
uartRxFullIRDone = 0;
uartRxHalfIRDone = 0;
}
}
Главный метод
void proj_main()
{
volatile const char *ch = ";V-F-BIN;ver: "VER_PROG(VER_a,VER_b,VER_c);(void)ch;//0x8008b00
HAL_Delay(1);//чтобы HAL_GetTick() не выдавал ноль
uart_startRecieving_MTF();//Начинаю принимать данные от mtf_02
while (1){
//хэндлеры
uart_Handler_MTF();
}//while (1)
}
Ссылка на скачивание исходного кода [ https://t.me/ChipCraft В закрепленном сообщении [ #исскуствомк_исходный_код -Исходный код для датчика MTF-02]
Вывод
Датчик MTF-02 — это отличное решение для проектов, требующих точного измерения перемещения без сложных навигационных систем. Его простота, низкая цена и энергоэффективность делают его популярным в робототехнике, дронах и умных устройствах.
Если статья показалась Вам интересной, буду рад выпустить для Вас еще множество статей исследований по всевозможным видам устройств, так что, если не хотите их пропустить – буду благодарен за подписку на мой ТГ-канал: https://t.me/ChipCraft.
Комментарии (6)
celladon
08.08.2025 10:08"Настоящая" камера глубины MaixSense A010 есть на Озоне. С такой дело не имели?
DM_ChipCraft Автор
08.08.2025 10:08Ого, очень интересно, к сожалению я не работал с камерами глубины, но мне очень интересно стало!!!! Спасибо Вам большое за предоставленную ссылку, я обязательно рассмотрю и постараюсь сделать качественный и интересный материал, как раз для работы с такими подобными устройствами, у меня есть процессоры ADSP Blackfin, будет интересно посмотреть :)
celladon
Интересно было бы получить изображение карты глубины. Это действительно камера глубины? Или просто датчик расстояния?
DM_ChipCraft Автор
К сожалению это не камера глубины, это просто датчик который выдает ось X , Y , высоту и т.д..
iliasam
У меня ощущение, что на фото в статье подписи перепутаны.
Слева как раз камера датчика движения - с крупной линзой, а справа - обычный "точечный" TOF датчик расстояния (вероятно, от ST). Хорошо видно, что у него две линзы: на прием, и на передачу.
В описании: https://micoair.com/optical_range_sensor_mtf-02/ никакая "Камера ToF" не упоминается.
DM_ChipCraft Автор
Спасибо большое за обнаружение моей ошибки, в моих заметках было записано к сожалению неправильно :), не перепроверил, обязательно исправлю