
▍ Немного о модельке, принципе работы и функции fail-safe
Давайте я расскажу про модель в целом и как всё это дело работает. Это HPI Baja 5B с двухтактным ДВС объёмом 26 куб. см, разгоняется примерно до 70км/ч в базовой комплектации.

Размеры и внешний вид. В конце статьи есть нарезка интересных моментов с ней
Управляется модель с пульта (передатчик), на борту имеется приёмник и АКБ для питания всей электроники. Бортового генератора в комплектации нет, да и наверное не существует на сегодняшний день моделей с генератором. Это дело техники и чуть позже я его обязательно приделаю.
В моём случае приёмник 6-канальный, 2 канала задействованы для приводов газ\тормоз и руля, остальные каналы на усмотрение фантазии. Приёмник формирует ШИМ сигналы для каждого канала в соответствии с положением управляющих элементов на передатчике.
Разъёмы на приёмнике имеют стандартную распиновку для подключения сервоприводов: GND-VCC-PWM.

Приёмник
Основных сервоприводов два. Первый управляет поворотом передних колёс (влево, вправо, тут всё просто). Второй привод управляет дроссельной заслонкой карбюратора и тормозными колодками (в одну сторону разгоняемся, в другую сторону тормозим). Управляется это с помощью тяги с пружинами.

Общая тяга для тормозов и дросселя

Тормозная система
Fail-safe это функция приёмника, которая срабатывает при потере сигнала. Она заставляет приёмник выставить сервоприводы в заранее установленное положение. Нужное положение задаётся в настройках через передатчик. В более простых приёмниках положение проводов жёстко прописаны в прошивке. Обычно это сброс газа в 0 и нажатие тормоза до упора. В этой функции и заключается проблема. Дело в том, что она работает только при нормально функционирующем приёмнике. Соответственно, если приёмник выйдет из строя, то функция fail-safe не сработает. Сгорел сервопривод дроссельной заслонки, последствия сами понимаете какие могут быть, особенно если он сгорел на полностью открытом дросселе. Отвалился провод от АКБ, потеряли питания, упало напряжение — аналогично. Нужно надёжно ограничиться от подобных проблем.
▍ О зажигании
После небольшого ликбеза можно углубиться в принцип работы зажигания двухтактного ДВС. Именно через манипуляции с системой зажигания управляется двигатель — его запуск и остановка.

Схема зажигания
Система зажигания в двигателе независимая и ей не нужен источник питания для работы. На маховике в месте воспламенения топливной смеси стоят два магнита.

Маховик
В процессе вращения маховика магниты проходят мимо катушки в блоке зажигания и возбуждают в ней напряжение, но его недостаточно для формирования искры — нам нужно больше напряжения. Блок зажигания содержит в себе трансформатор, который решает эту проблему. Он преобразует низкое напряжение в высокое, которого в паре с конденсатором уже достаточно для формирования искры.
Для остановки двигателя нужно заземлить низковольтную катушку на корпус двигателя, тем самым не давая зарядится конденсатору — нет искры, нет воспламенения топливной смеси. Для этого имеется кнопка Stop Engine. Всё просто.

Зажигание в сборе
▍ Немного подумаем
Исходя из теории выше, нам нужно просто удалённо нажать на кнопку «Stop Engine», т.е. соединить два провода и всё — двигатель остановлен. Для этой задачи прекрасно подойдёт реле, которое будет подключаться параллельно кнопке.
«Но почему реле? 21 век же, давай MOSFET!» — Нет. Чем хорошо реле? Даже в случае пропадания питания она вернётся в изначальное положение, т.е. мы получаем функцию защиты от пропадания питания из коробки (да, реле может залипнуть, но и MOSFET тоже имеет свои нюансы). Соответственно, разумнее всего подключаться к нормально закрытым контактам. У нас дополнительно ещё получается функция блокировки запуска двигателя. Без сигнала с передатчика двигатель завести не получится — тоже неплохо, незачем заводить двигатель без активного передатчика, как минимум это опасно.
На передатчике 6 каналов: 2 из них заняты, 2 канала представлены в виде потенциометров и их использовать для наших целей явно неудобно, 1 канал трёхпозиционный — тоже не то и 1 канал в виде кнопки. Вот кнопка нам и нужна, т.к. она работает как переключатель. После каждого нажатия меняется ширина импульса с 1000us до 2000us и наоборот.

Передатчик
У нас в итоге получается следующая последовательность для запуска двигателя:
- Включили передатчик;
- Включили приёмник;
- Разрешили запуск двигателя через кнопку на передатчике;
- Запустили двигатель.
Но есть один нюанс. Мы не можем напрямую подключить реле к приёмнику, т.к. он всегда выдаёт ШИМ сигнал. Нужно как-то преобразовать ШИМ в push-pull сигналы. Будем развлекаться по полной, берём фугасы — STM32F030. Да, микроконтроллер в этой задаче излишен и можно обойтись рассыпухой, но так неинтересно и пропадает гибкость. К тому же STM32F030 стоит копейки даже в виде demo board.
Я не стал делать отдельную плату для этого проекта и решил собрать всё на demo board. Ну и разумеется под пайку, ввиду вибраций использовать разъёмы нужно по минимуму.
▍ ТЗ
Нужен блок, который будет выключать зажигание двигателя в случаях:
- Пропадания сигнала с передатчика;
- Пропадания питания на блок;
- Пропадания питания на приёмник;
- Выхода из строя приёмника;
- Управляющего сигнала с передатчика (удалённое выключение);
- Работа блока не должна зависеть от бортового питания и приёмника.
В остальных случаях достаточно стандартного fail-safe на приёмнике, но наш блок включает в себя и его функционал. Этого вполне должно хватить для безопасного управления моделью. Конечно можно пойти ещё дальше и начать отвечать на вопросы «А что делать, если МК умер и реле всегда разомкнуто будет?». Я рассчитываю на то, что вероятность одновременного выхода из строя приёмника\сервопривода и нашего блока — мала.
▍ Реализация
В целом всё просто. Мы получаем с отдельного канала приёмника ШИМ сигнал, измеряем ширину импульса и управляем реле. Код получился крайне простой, я решил использовать решение в лоб — polling в цикле.
Импульсы идут с приёмника c постоянной частотой (обычно это от 20Hz до 300Hz), соответственно для определения неисправности приёмника будем использовать это свойство — таймаут между импульсами. Таймаута в 200ms более чем достаточно для этой задачи, т.е. если импульс не был получен в течении 200ms, то блок впадает в цикл, в котором переключает реле и останавливает двигатель. Повторный запуск возможен после повторной подачи питания или перезагрузки блока.
Исходный код:
// *************************************************************************** /// @file main.c /// @author NeoProg // *************************************************************************** #include "project_base.h" #include "systimer.h" static void system_init(void); void fail_safe_loop() { while (true) { gpio_set(GPIOA, 10); } } int main() { system_init(); systimer_init(); gpio_set_mode(GPIOA, 9, GPIO_MODE_INPUT); gpio_set_pull(GPIOA, 9, GPIO_PULL_DOWN); gpio_set(GPIOA, 10); gpio_set_mode(GPIOA, 10, GPIO_MODE_OUTPUT); gpio_set_output_type(GPIOA, 10, GPIO_TYPE_OPEN_DRAIN); TIM14->PSC = APB1_CLOCK_FREQUENCY / 100000; TIM14->CNT = 0; delay_ms(1000); uint64_t start_timeout = get_time_ms(); while (true) { start_timeout = get_time_ms(); while (gpio_read_input(GPIOA, 9) == 0) { if (get_time_ms() - start_timeout > 200) { fail_safe_loop(); } } TIM14->CR1 &= ~TIM_CR1_CEN; TIM14->CNT = 0; TIM14->CR1 = TIM_CR1_CEN; start_timeout = get_time_ms(); while (gpio_read_input(GPIOA, 9) == 1) { if (get_time_ms() - start_timeout > 200) { fail_safe_loop(); } } TIM14->CR1 &= ~TIM_CR1_CEN; uint16_t width = TIM14->CNT; if (width > 1700) { gpio_reset(GPIOA, 10); } else { gpio_set(GPIOA, 10); } continue; } } /// *************************************************************************** /// @brief System initialization /// @param none /// @return none /// *************************************************************************** static void system_init(void) { // Enable Prefetch Buffer FLASH->ACR = FLASH_ACR_PRFTBE; // Configure PLL (clock source HSI/2 = 4MHz) RCC->CFGR |= RCC_CFGR_PLLMULL12; RCC->CR |= RCC_CR_PLLON; while ((RCC->CR & RCC_CR_PLLRDY) == 0); // Set FLASH latency FLASH->ACR |= FLASH_ACR_LATENCY; // Switch system clock to PLL RCC->CFGR |= RCC_CFGR_SW_PLL; while ((RCC->CFGR & RCC_CFGR_SWS_PLL) == 0); // Enable GPIO clocks RCC->AHBENR |= RCC_AHBENR_GPIOAEN; // Enable TIM14 clocks RCC->APB1ENR |= RCC_APB1ENR_TIM14EN; }
По железу получилось не очень красиво, скорее всего, сделаю отдельную плату.

Кликабельно
▍ Результаты
В целом устройство получилось крайне простым и дешёвым в изготовлении, а также достаточно надёжным.
Вот так это выглядит на самой модели (фото ниже). Располагается блок в безопасном месте под металлической крышкой клетки безопасности. От коробки идут 2 жгута: один на кнопку «Stop Engine», другой на приёмник.

Кликабельно
▍ Небольшие новости по гескаподу (AIWM Hexapod)
В данный момент проект на паузе, я от него немного устал и решил переключиться на другие проекты. Соответственно, статей по гексу в ближайшее время не будет, но будут другие не менее интересные (ну я надеюсь они интересные были) 🙂
▍ Погоняем
▍ Новости по будущим проектам
Сейчас я работаю над системой слежения за солнцем (солнечный трекер), солнечные панели, датчики, все дела. Достаточно интересный и не очень сложный проект, но полон нюансов. В скором времени будет статья, в которой я опишу все подробности и посмотрим как это работает 🙂
Telegram-канал и уютный чат для клиентов
ссылка на оригинал статьи https://habr.com/ru/company/ruvds/blog/683928/

Добавить комментарий