Блок удаленного выключения зажигания двухтактных ДВС

d57ywodgappqlkn_s8vvlhlrewa.png

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

▍ Немного о модельке, принципе работы и функции fail-safe


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

nwzimixvpaxfatifq303c5inooi.png

Размеры и внешний вид. В конце статьи есть нарезка интересных моментов с ней

Управляется модель с пульта (передатчик), на борту имеется приёмник и АКБ для питания всей электроники. Бортового генератора в комплектации нет, да и наверное не существует на сегодняшний день моделей с генератором. Это дело техники и чуть позже я его обязательно приделаю.

В моём случае приёмник 6-канальный, 2 канала задействованы для приводов газ\тормоз и руля, остальные каналы на усмотрение фантазии. Приёмник формирует ШИМ сигналы для каждого канала в соответствии с положением управляющих элементов на передатчике.

Разъёмы на приёмнике имеют стандартную распиновку для подключения сервоприводов: GND-VCC-PWM.
mi0xwbzt5vozavdjssplcjd9zhi.png
Приёмник

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

wdvg7qxyxpvcphzsw0skbgqozqi.png
Тормозная система

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

▍ О зажигании


После небольшого ликбеза можно углубиться в принцип работы зажигания двухтактного ДВС. Именно через манипуляции с системой зажигания управляется двигатель — его запуск и остановка.

j-sdhgrbomxw8o_zhxajrpr0aq8.png

Схема зажигания

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

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

Для остановки двигателя нужно заземлить низковольтную катушку на корпус двигателя, тем самым не давая зарядится конденсатору — нет искры, нет воспламенения топливной смеси. Для этого имеется кнопка Stop Engine. Всё просто.

lgv-fqwh0on0zhqmsnhdfxvy-xu.png
Зажигание в сборе

▍ Немного подумаем


Исходя из теории выше, нам нужно просто удалённо нажать на кнопку «Stop Engine», т.е. соединить два провода и всё — двигатель остановлен. Для этой задачи прекрасно подойдёт реле, которое будет подключаться параллельно кнопке.

«Но почему реле? 21 век же, давай MOSFET!» — Нет. Чем хорошо реле? Даже в случае пропадания питания она вернётся в изначальное положение, т.е. мы получаем функцию защиты от пропадания питания из коробки (да, реле может залипнуть, но и MOSFET тоже имеет свои нюансы). Соответственно, разумнее всего подключаться к нормально закрытым контактам. У нас дополнительно ещё получается функция блокировки запуска двигателя. Без сигнала с передатчика двигатель завести не получится — тоже неплохо, незачем заводить двигатель без активного передатчика, как минимум это опасно.

На передатчике 6 каналов: 2 из них заняты, 2 канала представлены в виде потенциометров и их использовать для наших целей явно неудобно, 1 канал трёхпозиционный — тоже не то и 1 канал в виде кнопки. Вот кнопка нам и нужна, т.к. она работает как переключатель. После каждого нажатия меняется ширина импульса с 1000us до 2000us и наоборот.

0s7ojdkots_eb5v6dd0wkog-avq.png

Передатчик

У нас в итоге получается следующая последовательность для запуска двигателя:

  1. Включили передатчик;
  2. Включили приёмник;
  3. Разрешили запуск двигателя через кнопку на передатчике;
  4. Запустили двигатель.


Но есть один нюанс. Мы не можем напрямую подключить реле к приёмнику, т.к. он всегда выдаёт ШИМ сигнал. Нужно как-то преобразовать ШИМ в 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;
}


По железу получилось не очень красиво, скорее всего, сделаю отдельную плату.

upwtub4z0nbzvslxilvxat44qaa.png

Кликабельно

▍ Результаты


В целом устройство получилось крайне простым и дешёвым в изготовлении, а также достаточно надёжным.

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

mdoupmu7c9_wkxzge1ol1aicftu.png

Кликабельно

▍ Небольшие новости по гескаподу (AIWM Hexapod)


В данный момент проект на паузе, я от него немного устал и решил переключиться на другие проекты. Соответственно, статей по гексу в ближайшее время не будет, но будут другие не менее интересные (ну я надеюсь они интересные были) :)

▍ Погоняем


▍ Новости по будущим проектам


Сейчас я работаю над системой слежения за солнцем (солнечный трекер), солнечные панели, датчики, все дела. Достаточно интересный и не очень сложный проект, но полон нюансов. В скором времени будет статья, в которой я опишу все подробности и посмотрим как это работает :)

Telegram-канал и уютный чат для клиентов

sz7jpfj8i1pa6ocj-eia09dev4q.png

© Habrahabr.ru