Датчик оптического потока - MTF02

Датчик оптического потока - MTF02

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

                                                    Оптический датчик MTF-02
                                                    Оптический датчик MTF-02

В конструкции датчика 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:

  1. ToF motion sensor — технология измерения расстояния до объекта с помощью времени задержки отраженного сигнала (лазерного или ИК-импульса). Точечные датчики измеряют дистанцию до одной точки.
  2. Оптический поток (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

            Сигнал TX датчика MTF-02 подключается к STM32F103(PA10-31 контакт -                                         RX), а так же +5В и GND
            Сигнал TX датчика MTF-02 подключается к STM32F103(PA10-31 контакт -                                         RX), а так же +5В и GND

Для более стабильного напряжения питания можно использовать следующую схему, в которой работает понижающий преобразователь MP2315, но необходим источник +12В, в моем случае используется аккумуляторная сборка (NiMH/Pb +12В).

                           Понижающий преобразователь напряжения [ +12V до +5V  ]
                           Понижающий преобразователь напряжения [ +12V до +5V ]

Вид осциллограммы передаваемых данных модуля MTF-02 по интерфейсу USART (линия TX)

Датчик оптического потока - MTF02

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

Настройка интерфейса USART в микроконтроллере STM32F103
Настройка интерфейса USART в микроконтроллере STM32F103
  • В пункте [ 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; }

Обработка и расшифровка данных 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) }

Ссылка на скачивание исходного кода [ #исскуствомк_исходный_код -Исходный код для датчика MTF-02]

Вывод

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

Если статья показалась Вам интересной, буду рад выпустить для Вас еще множество статей исследований по всевозможным видам устройств, так что, если не хотите их пропустить – буду благодарен за подписку на мой ТГ-канал: https://t.me/ChipCraft.

Начать дискуссию