ARDUINO Блок опережения зажигания ДВС

esperoty

✩✩✩✩✩✩✩
14 Дек 2020
1
0
Всем привет!

Увидел одно решение на ардуино, и мне очень понравилась эта идея. https://www.youtube.com/watch?v=XP1SUmiTKZY
Сейчас в работе следующая задача:
Для мотоцикла необходимо реализовать электронное опережение момента, когда искра воспламеняет топливную смесь.
В зависимости от оборотов двигателя необходимо успеть зажечь смесь, чтобы она выдавала наибольшее усилие при взрыве, и обратная ситуация, чтобы не поджечь раньше - тогда сила от воспламенения сыграет в обратную сторону.
С программированием не сильно знаком, но разобраться получается, как прописать диапазоны по оборотам понял, и формулы расчетов углов.
Вопросы, с которыми столкнулся, и хотелось бы найти решение:
  1. посоветовали операторы if else заменить на switch case т.к. вторые тратят меньше ресурсов при расчете - так ли в моем конкретном случае или нет разницы?
  2. для вычислений угла поворота возможно ли перевести в uint16 / unsigned int (0...65535), а угол опережения - в uint8 / byte (0...255) вместо текущих расчетов, способствует ли это сокращению расходования ресурсов?
  3. в текущей реализации используется один выход pinMode(1, OUTPUT), мне необходимо задействовать второй выход, полагаю, что можно использовать "4" и прописать для него сигнал либо в формате через n градусов угла оборота после сигнала из выхода "1" либо в постоянный % который будет применяться на всем диапазоне оборотов коленчатого вала.

По первым двум вопросам прошу совета: стоят ли свеч эти предложения, т.к. для меня это долгий процесс, хотя понимаю, что операции наверно одни из типичных. Если смысл в этом есть прошу помочь сделать или сказать как.
По третьему вопросу интересует как сделать и какой выход задействовать.

Плата digispark attiny85

Вот что получилось на текущий момент:

igntionsystem:
unsigned long newtime;
unsigned long oldtime;
unsigned long diffTime;
unsigned long VMTtime;
unsigned long nextIgnition = 0;
long int rpm;
bool modulator;
bool ignitionWasFired;
bool ignitionFlag;
bool ignitionFlagWithOffset;
bool oldModulator;
float ignitionDegree;



void setup()

{
   newtime=micros();
   oldtime=micros();
//  Serial.begin(115200); //Default Baudrate
  pinMode(1, OUTPUT);
  pinMode(0, INPUT);
//  Serial.print("LOADED");
}

void readrpm()
{
  newtime=micros();
  diffTime = newtime-oldtime;
  rpm = 60000000/diffTime;
//  Serial.print("RPM");
//  Serial.print(rpm);
}

void countIgnitionTime() {
  nextIgnition = (500000 * (360 - ignitionDegree)) / (3 * rpm) + VMTtime;
  ignitionFlagWithOffset = true;
}

void loop() {
 
  modulator = digitalRead(0);
  if (micros() >= nextIgnition && ignitionFlagWithOffset == true) {
    digitalWrite(1, HIGH);
    ignitionFlagWithOffset = false;
  }
//  if (ignitionFlag == false) {
//    digitalWrite(1, LOW);
//  }

  if (ignitionFlag == true) {
    digitalWrite(1, HIGH);
    ignitionFlag = false;
  }
  if (modulator != oldModulator) {
    oldModulator = modulator;
    
    if(modulator == LOW) {
      digitalWrite(1, LOW);
      return;
    }
    
    VMTtime = micros();

    // 1000-20.8; 2000-17; 3000-19.8; 4000-20.1; 5000-22.4; 6000-25

    readrpm();
    ignitionFlag = true;
    if (rpm >= 0 && rpm <= 600) {
        oldtime=micros();
        ignitionFlag = true;
        return;
    }
    if (rpm >= 600 && rpm <= 800) { // 0 - 10.8
       ignitionDegree = 0.0540 * rpm + (-32.400);
     }
     if (rpm >= 800 && rpm <= 1000) { // 10.8 - 20.8
       ignitionDegree = 0.0500 * rpm + (-29.200);
     }
     if (rpm >= 1000 && rpm <= 1500) { // 20.8 - 18.6
       ignitionDegree = 0.0044 * rpm + (-25.200);
     }
     if (rpm >= 1500 && rpm <= 2000) { // 18.6 - 17
       ignitionDegree = 0.0032 * rpm + (-23.400);
     }
     if (rpm >= 2000 && rpm <= 2500) { // 17 - 18.4
       ignitionDegree = 0.0028 * rpm + (11.400);             
     }
     if (rpm >= 2500 && rpm <= 3000) {// 18.4 - 19.8
       ignitionDegree = 0.0028 * rpm + (11.400);
     }
     if (rpm >= 3000 && rpm <= 3500) { // 19.8 - 21.4
       ignitionDegree = 0.0032 * rpm + (10.200);
     }
     if (rpm >= 3500 && rpm <= 4000) { // 21.4 - 20.1
       ignitionDegree = 0.0026 * rpm + (-30.500);             
     }
     if (rpm >= 4000 && rpm <= 4500) { // 20.1 - 21.4
       ignitionDegree = 0.0026 * rpm + (9.700);
     }
     if (rpm >= 4500 && rpm <= 5000) { // 21.4 - 22.4
       ignitionDegree = 0.0020 * rpm + (12.400);
     }
     if (rpm >= 5000 && rpm <= 5500) { // 22.4 - 23.9
       ignitionDegree = 0.0030 * rpm + (7.400);
     }
     if (rpm >= 5500 && rpm <= 6000) { // 23.9 - 25
       ignitionDegree = 0.0022 * rpm + (11.800);
     }
     if (rpm >= 6000 && rpm <= 6500) { // 25 - 26.7
       ignitionDegree = 0.0034 * rpm + (4.600);                           
     }
     if (rpm > 6500) {
       ignitionDegree = 26.7;
     }

    if (ignitionDegree > 0){
      countIgnitionTime(); 
    }
    oldtime=micros();
  }
}
 

Slavik56

✩✩✩✩✩✩✩
2 Мар 2021
4
0
Привет . Использовал твой скетч для 4т скутера)) . что за углы ? У моего скутера будто звук отключили , явно мне эти углы не подходят ,динамика ухудшелась. Внимание вопрос как мне изменить углы?

откуда это бралось ignitionDegree = 0.0032 * rpm + (10.200);
конкретно вот эти значения
0.0028
............
0.0032 и так далие
 
Изменено:

Slavik56

✩✩✩✩✩✩✩
2 Мар 2021
4
0
ПРИВЕТ! Тоже интересна эта тема, расскажи что вышло в итоге?
Подсоединил Ардуино в разрыв датчика. С начала была какая то разница по сравнению со стоковым зажиганием. Потом я заметил что при выключенном Ардуино всё работает также сигнал проходит в коммутатор. Я не специалист и не могу понять как так получается. Пины прозванивал мультиметром КЗ нет. Кажется без доработок эта схема не сработает , так как сигнал от датчика аналоговый а нужен цифровой. Нужно менять датчик на оптический и дорабатывать под него всё. Также нужно поставить датчик дроссельной заслонки иначе что бы были оптимальные УОЗ нужно давить газ в пол.
 

Кирилл Перминов

✩✩✩✩✩✩✩
25 Июн 2020
26
0
я так полагаю, что ардуино должна смещать УОЗ в большую сторону, но с запаздыванием на одни оборот КВ, что бы понимать на сколько по сравнению с предыдущим, нужно только график зависимости УОЗ от оборотов КВ
 

Slavik56

✩✩✩✩✩✩✩
2 Мар 2021
4
0
я так полагаю, что ардуино должна смещать УОЗ в большую сторону, но с запаздыванием на одни оборот КВ, что бы понимать на сколько по сравнению с предыдущим, нужно только график зависимости УОЗ от оборотов КВ
По идее Ардуино принимает сигнал с датчика и выдает другой сигнал заданый алгоритмом он может и опережать и запаздывать. Но как получается по факту не известно.
 

Кирилл Перминов

✩✩✩✩✩✩✩
25 Июн 2020
26
0
Сигнал по форме тот же, по сути просто импульс 12 вольт. Ардуино снимает сигнал с Датчика Холла (ДХ), замеряет частоту, и по графику смещает УОЗ. Но так как в уже произошедшем искрообразовании она не может ничего поменять, получается смещается в следующем. У меня двух цилиндровый мотор, значит в следующем цилиндре УОЗ будет уже откорректированный по предыдущему, в 4-х цилиндровом аналогично в следующем по предыдущему
 

Эдуард Анисимов

★★★★★★✩
23 Сен 2019
2,407
976
58
Марий-Эл
Для правильной установки угла зажигания нужно:
Мерять обороты.
Расход воздуха.
Температуру двигателя.
Температуру воздуха на входе.
И никто и никогда не рассчитывает угол опережения на ходу.
Эти углы прошиты в "карты зажигания".
Эти карты рассчитываются заранее для каждой модели двигателя и выбираются в зависимости от входных параметров.
Тем более ардуина не способна такие расчёты вести в реальном масштабе.
А если в интернете что то такое видели. Ну что ж. На лифте то же много чего написано, тем не менее он поднимается на стальном тросе. А инфа в инете на 90% полный п.. , т.е. неправда.
 
  • Лойс +1
Реакции: Slavik56

Кирилл Перминов

✩✩✩✩✩✩✩
25 Июн 2020
26
0
Для правильной установки угла зажигания нужно:
Мерять обороты.
Расход воздуха.
Температуру двигателя.
Температуру воздуха на входе.
И никто и никогда не рассчитывает угол опережения на ходу.
Эти углы прошиты в "карты зажигания".
Эти карты рассчитываются заранее для каждой модели двигателя и выбираются в зависимости от входных параметров.
Тем более ардуина не способна такие расчёты вести в реальном масштабе.
А если в интернете что то такое видели. Ну что ж. На лифте то же много чего написано, тем не менее он поднимается на стальном тросе. А инфа в инете на 90% полный п.. , т.е. неправда.
Всё так, но на зажигании как правило есть механический регулятор УОЗ, он в зависимости от оборотов за счёт центробежной силы смещает кулачок прерывателя, у меня была идея имитировать его работу через ардуино. Тем самым убрать подвижные части и устранить неточности в работе. На китайской технике иногда даже такого не предусмотрено, но и найти график к ней проблематично, только подбирать
 

rGlory

★✩✩✩✩✩✩
11 Май 2021
200
20
Судя по схеме там на вход ATtiny 12В с датчика хола фигачат? Или этот коммутатор его от 5В питает?
 

te238s

★★✩✩✩✩✩
14 Ноя 2021
374
97
Это первое что бросается в глаза. Это не есть хорошо,заниматься делением в таких критичных местах.
Как делал я:
1.таймер в режиме захвата измеряет период каждого цикла,от вспышки до вспышки. Либо по сигналам от датчика положения КВ,либо от генератора(что проще всего)
2. Соответствие периода вращения и УОЗ просчитывается ЗАРАНЕЕ и храниться в массиве,дабы не тратить зря драгоценные ресурсы маленькой Тиньки.
3. Каждый цикл мотора,зная период дастаем нужные значения.
Можно считать и "на лету",но только категорически без делений! Либо брать камень помощней,например stm32.Плюсы моего подхода: критические моменты обрабатываются в прерывании,МК большую часть времени простаивает,а значит можно и ПИД-регулятор замутить чтоб учитывалась динамика. Алгоритм будет знать как сильно ускоряется-замедляется мотор,соответственно и УОЗ корректировать.
 

te238s

★★✩✩✩✩✩
14 Ноя 2021
374
97
И никто и никогда не рассчитывает угол опережения на ходу.
Скажу больше. Оптимальных расчетов не существует. Чем-то всегда жертвуют. Здесь же задача не баллистическую ракету запустить. Для "бытовых" целей этой точности достаточно. Достаточно знать обороты и степень открытия дросселя.
 

user314

★✩✩✩✩✩✩
26 Апр 2022
45
38
Решил попробовать ФУОЗ на старичке Т-200 (мотор от тулицы), под рукой ардуино не оказалось, зато есть esp8266 на плате WEMOS D1.
Так вот изначально к заводскому контактному зажиганию был приделан транзисторный модуль на MOSFET, работает в общем не плохо, но захотелось ФУОЗ и вот такая схема получилась:

esp8266_ignition.JPG

Скетч был изначально взят с сайта custom-cult, только состояния выхода (GPIO5) инвертированы на противоположные, так чтобы коммутатор работал согласно положению прерывателя.

Скетч:
unsigned long newtime;
unsigned long oldtime;
unsigned long diffTime;
unsigned long VMTtime;
unsigned long nextIgnition = 0;
long int rpm;
bool modulator;
bool ignitionWasFired;
bool ignitionFlag;
bool ignitionFlagWithOffset;
bool oldModulator;
float ignitionDegree;

void setup()
{
  newtime=micros();
  oldtime=micros();
  pinMode(5, OUTPUT); // D1 To driver
  pinMode(4, INPUT); // D2 from interruptor
  pinMode(2, OUTPUT); // LED
  digitalWrite(2, LOW); // LED ENABLED
}

void readrpm()
{
  newtime=micros();
  diffTime = newtime-oldtime;
  rpm = 60000000/diffTime;
}

void countIgnitionTime() {
  nextIgnition = (500000 * (360 - ignitionDegree)) / (3 * rpm) + VMTtime;
  ignitionFlagWithOffset = true;
}


void loop() {
//  if(modulator == LOW && micros() - oldtime >= 1500000) {
//    digitalWrite(5, LOW);
//  }

  modulator = digitalRead(4);
  if (micros() >= nextIgnition && ignitionFlagWithOffset == true) {
    digitalWrite(5, LOW); // Изменён с HIGH
    ignitionFlagWithOffset = false;
  }
//  if (ignitionFlag == false) {
//    digitalWrite(5, LOW);
//  }

  if (ignitionFlag == true) {
    digitalWrite(5, LOW); // Изменён с HIGH
    ignitionFlag = false;
  }
  if (modulator != oldModulator) {
    oldModulator = modulator;
   
    if(modulator == LOW) {
      digitalWrite(5, HIGH); // Изменён с LOW
      return;
    }
   
    VMTtime = micros();

    readrpm();
    ignitionFlag = true;
    if (rpm >= 0 && rpm <= 700) {
        oldtime=micros();
        ignitionFlag = true;
        return;
    }
   
    if (rpm >= 700 && rpm <= 1000) {
      ignitionDegree = 0.000 * rpm + (0.000);
    }
    if (rpm >= 1000 && rpm <= 2000) {
      ignitionDegree = 0.000 * rpm + (0.000);
    }
    if (rpm >= 2000 && rpm <= 3000) {
      ignitionDegree = 0.000 * rpm + (0.000);
    }
    if (rpm >= 3000 && rpm <= 4000) {
      ignitionDegree = 0.000 * rpm + (0.000);
    }
    if (rpm > 4000) {
      ignitionDegree = 0;
    }
   
     
    /*
    if (rpm >= 700 && rpm <= 1000) {
      ignitionDegree = 0.003 * rpm + (-2.333);
    }
    if (rpm >= 1000 && rpm <= 2000) {
      ignitionDegree = 0.002 * rpm + (-1.000);
    }
    if (rpm >= 2000 && rpm <= 3000) {
      ignitionDegree = 0.003 * rpm + (-3.000);
    }
    if (rpm >= 3000 && rpm <= 4000) {
      ignitionDegree = 0.004 * rpm + (-6.000);
    }
    if (rpm > 4000) {
      ignitionDegree = 10;
    }
    */

    if (ignitionDegree > 0){
      countIgnitionTime();
    }
    oldtime=micros();

  }
}
Сам по себе как коммутатор устройство работает нормально (с отключенным ФУОЗ), проверял с фиксированным опережением на уровне 23 градуса до ВМТ, влияние наводок можно исключить. Но как только включаешь закомментированный код, взамен нулевым значениям, то есть собственно само смещение - начинаются глюки, мотор при трогании дёргается и явно пропускает такты, получается детонация.

Изначально выставлял прерыватель на угол 0 градусов, думал что мотор не хочет работать в таком режиме, но опытным путём выяснил, что коммутатор глючит именно в режиме ФУОЗ в независимости от выставленных углов, хоть 1 градус поставь - начинает глючить.

Пробовал схему испытывать на стенде подавая импульсы с генератора сигналов (в идеале надо имитировать прерыватель, но нечем пока), по осциллографу пропусков импульсов на выходе не обнаружил, ФУОЗ гонял по разным частотам - всё в порядке, опережение есть и оно ожидаемо как в коде.

В чём проблема не могу догнать.
 
  • Лойс +1
Реакции: UJV 5901

te238s

★★✩✩✩✩✩
14 Ноя 2021
374
97
if (rpm >= 700 && rpm <= 1000) { ignitionDegree = 0.003 * rpm + (-2.333);
Если внимательно посмотреть,то при значениях 700...777,666 результат отрицательный.
И вообщ что за магические цифры? Так не делается.
А вообще правильней все данные представлять в периодах: время оборота,время от ВМТ до искры и т.д. тогда делений можно избежать.
Кривую характеристики принято в табличном виде делать,безо всяких проверок условий. Оно и наглядней.
 

PiratFox

★★★★★✩✩
13 Фев 2020
1,706
474
@user314, ещё проблема в дребезге контактов прерывателя. В коде никак не реализована защита от него. Понятно, что от генератора сигналов всё работает нормально.
 

te238s

★★✩✩✩✩✩
14 Ноя 2021
374
97
А что такое Modulator и ignitionflag? Логика алгоритма выше всяческих похвал. Тот случай,когда проще написать заново.

if (rpm >= 3000 && rpm <= 4000) { ignitionDegree = 0.000 * rpm + (0.000);
Ржунимагу))))
Далее тупо костыль
if (ignitionDegree > 0){ countIgnitionTime();
Но это были придирки.
Стробоскоп в помощь. Надо понять что там в реале он выдаёт и в какой момент. Осциллом хотя бы померь на двигателе вход и выход. Возможно что вычисления в корне не верны и искра далеко за пределами разумных углов. Осциллограф двухканальный? Сможете замерить хотя бы на столе тайминги входа-выхода при конкретных оборотах?
Кстати,открою маленький секрет. Все эти углы опережения вторичны,и они бесполезны. Первично время горения,а оно постоянно. И расчёты сводятся к простой арифметике: от времени оборота вычитаем скорость горения(утрируя,пусть 5мс) получаем время от ВМТ до искры.
 
Изменено:

user314

★✩✩✩✩✩✩
26 Апр 2022
45
38
Ржунимагу))))
Далее тупо костыль
Это оно и есть, первое что пришло на ум не меняя сути кода.

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

te238s

★★✩✩✩✩✩
14 Ноя 2021
374
97
@user314,двигатель спокойно воспримет скакание углов на 20 градусов,попытайся посчитать сколько там угол пляшет и на каких оборотах. А пляшет,кстати,из-за
Т.к. часть значений ввиду отрицательности,он не учитывает.
Как вариант,осциллом посмотреть сигнал с прерывателя. Для этого написать в Лупе всё закомментить,и написать примерно это:
ДиджиталВрайт(5,ДиджиталРид(4)).
Увидим как МК воспринимает сигнал.
 
Изменено:

user314

★✩✩✩✩✩✩
26 Апр 2022
45
38
@te238s

А как вы думаете, почему я не спешу показывать изображения с осциллографа? :rolleyes:
А потому что он сложен для подобных задач:
IMG_5395.JPG
IMG_5396.JPG
Ну и тем не менее, надеюсь, видно что никаких аномалий нет, верхний (жёлтый) график это со стока ключевого транзистора, а нижний (красный) это с прерывателя.

Это вот с таким скетчем:
C++:
void setup() {
  pinMode(5, OUTPUT); // D1 To driver
  pinMode(4, INPUT); // D2 from interruptor
  pinMode(2, OUTPUT); // LED
  digitalWrite(2, LOW); // LED ENABLED
}

void loop() {
  digitalWrite(5, !digitalRead(4));
}
 

user314

★✩✩✩✩✩✩
26 Апр 2022
45
38
@te238s
с отрицанием, потому что в контактном зажигании искра образуется при размыкании, драйвер PC923 сигнал с контроллера не инвертирует, поэтому вот так. Дополнительную логику лепить не стал, потому что подумал что и через контроллер можно задать то что нужно.

Стенд на столе разобрал, так как сам по себе бесполезен, никаких проблем не выявляет.
 

te238s

★★✩✩✩✩✩
14 Ноя 2021
374
97
Мне кажется все таки есть различия. Возможно паразитные импульсы напряжения другие. Можно попробовать мосфет шунтировать,надо только посчитать емкость и сопротивление.
А вообще проверь,может мк сбрасывается. В setup введи задержку,например 1 секунду. Заглохнет ли двс.