Блок удаленного выключения зажигания двухтактных ДВС
Не уверен, что данная тематика подойдёт для хабра, но я попробую, вдруг будет интересно статьи в подобном плане. Начнём с предыстории. Став обладателем техники в масштабе 1\5 с ДВС, я задумался о безопасности. Дело в том, что встроенной в приёмник функции защиты от сбоя (fail-safe) недостаточно и при выходе из строя приёмника или АКБ машина просто уедет дальше в закат, т.к. модель оснащена двухтактным ДВС с независимым зажиганием. Получается, что у нас двигатель живёт сам по себе и нужно придумать независимую систему его выключения в случае сбоя.
▍ Немного о модельке, принципе работы и функции 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-канал и уютный чат для клиентов