ФУОЗ по дешману | OPPOZIT.RU | мотоциклы Урал, Днепр, BMW | оппозитный форум, ремонт и тюнинг мотоциклов
Home

ФУОЗ по дешману

оппозитчик kimba
чтоб поменять аватар - читай FAQ
нахождение: Москва, Ясенево

Ребята на базе ардуино запилили фуоз, дешево и просто
https://www.youtube.com/watch?v=XP1SUmiTKZY
Каково мнение общественности?
Думаю надо попробовать, ради эксперимента.
Ссылки на инструкцию
https://customcult.netlify.app/

РЕКЛАМА's picture

Прикольная тема. Пойду закажу себе парочку платок у китайцев на эксперименты..

белый1's picture

Уже заказал :) попробуем

kapotov's picture

Кто сделает отпишитесь , результат очень интересен.

BuffoG's picture

Интересная тема, послежу. Давно подумывал про ФУОЗ на ардуинке, но пока знаний по написанию кода не хватает.
___________________________________________________________________
"Человека можно уничтожить, но его нельзя победить" (Э. Хемингуэй)

Esperoty's picture

Интересная тема.
Удалось пока вроде разобраться с углами опережения, можно в самом скетче прописать более детальный диапазон, например с шагом в 500об/мин
Пока не понял, можно ли сделать второй сигнал через нужное время. Вроде выход Р4 можно использовать, но до конца не разобрался.

РЕКЛАМА's picture

Второй сигнал зачем? На 4 горшка?
Кстати вопросик, в этом зажигании имеет значение разница в пропорциях шторка-окно, как оно обороты считает? На ютубе задал вопрос создателям сего, но они чего-то игнорируют...

Esperoty's picture

Что я для себя вывел, т.к. зажигание выставляется уже в момент зажигания, надо углы прописывать с этим вычетом.
Обороты считает по сигналам от датчика (холла или опто) один сигнал - один оборот кв
nextIgnition = (500000 * (360 - ignitionDegree)) / (3 * rpm) + VMTtime;

Ниже задаётся для каких оборотов как угол использовать (но через формулу, в экселе подобрать удалось обратным методом)

Второй сигнал в целом можно использовать и для двух свечей в один цилиндр, и для v-моторов, и пр.

РЕКЛАМА's picture

проще наверно вторую такую платку подвесить, со своим отдельным датчиком.
А вот сделать как в сарумановском несколько графиков, хотя-бы два, уже интереснее.

Esperoty's picture

Тогда другую платку надо брать с большим объёмом памяти , либо несколько плат ардуино иметь и переключать их.

Artegro's picture

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

(Скетч использует 2970 байт (49%) памяти устройства. Всего доступно 6012 байт.
Глобальные переменные используют 41 байт динамической памяти.)

вот цикл подсчета угла от оборотов и у меня большой вопрос возникает , график то получается не линейный..... с разрывами п... и плоской полкой после 4000 рпм
( if (rpm >= 700 && rpm <= 1000) { // 0 - 2.2
ignitionDegree = 0.007 * rpm + (-5.133);
}
if (rpm >= 1000 && rpm <= 2000) { // 2.2 - 15
ignitionDegree = 0.013 * rpm + (-10.600);
}
if (rpm >= 2000 && rpm <= 3000) { // 15 - 25.1
ignitionDegree = 0.013 * rpm + (-11.000);
}
if (rpm >= 3000 && rpm <= 4000) {// 25.1 - 33.7
ignitionDegree = 0.007 * rpm + (7.000);
}
if (rpm > 4000) {
ignitionDegree = 33.7;
})

Esperoty's picture

Именно эту часть поправил, чтобы без разрывлв было, пример куска ниже., с чем удалось поиграться. Как прописать сдвиг например в формате + n градусов или + %
И свыше каких-то оборотов можно вывести на нужную полку как сделано у ребят. У меня скетч получился с учетом детализации на 60%, и пришлось коэффициент до 4го знака прописывать

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 > 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;
}

PCDeath's picture

Quote:
if (rpm > 1000 && rpm <= 1500) { // 20.8 - 18.6
ignitionDegree = 0.0044 * rpm + (25.200);

Знак забыл. У тебя тут получается 69,2 градуса угол. В космос улетит.

Рекомендовал бы оптимизировать расчёты, т.к. у ATMega/ATTiny нет блока для расчётов с плавающей точкой, и операции с дробными числами стоят дорого.
Текущий угол поворота можно перевести в uint16 / unsigned int (0...65535), а угол опережения - в uint8 / byte (0...255) - это освободит память и ускорит вычисления. Можно будет ещё каких свистелок-перделок напихать. :-)

Опять же, куча последовательных IF, когда может быть истинно только одно условие в один момент времени, не имеет смысла и будет тратить ресурсы, т.к. проверка не закончится на первом попавшемся истинном условии, а каждое будет проверяться на истинность. Лучше использовать CASE (как альтернатива - ELSE IF, но CASE красивее выглядит).

Но больше всего меня, конечно, беспокоит помехозащищённость. Я пока не победил наводки на Мегу от системы зажигания.

Peacedeath подкрался незаметно, но слышен был издалека

Esperoty's picture

За знак спасибо, упустил при копипасте.

Я с программированием не очень знаком, если по переводу uint16 и uint8, а также IF ELSE в SWITCH CASE подскажешь, это очень поможет :)

Если дальше отодвинуть от системы зажигания?

Artegro's picture

как то так
if (rpm >= 700 && rpm <= 1000) { // 0 - 2.2
ignitionDegree = 0.007 * rpm + (-5.133);
}
else if (rpm > 1000 && rpm <= 2000) { // 2.2 - 15
ignitionDegree = 0.013 * rpm + (-10.600);
}
else if (rpm > 2000 && rpm <= 3000) { // 15 - 25.1
ignitionDegree = 0.013 * rpm + (-11.000);
}
else if (rpm > 3000 && rpm <= 4000) {// 25.1 - 33.7
ignitionDegree = 0.007 * rpm + (7.000);
}
else if (rpm > 4000) {
ignitionDegree = 33.7;
}

PCDeath's picture

Ага. Только комменты всё равно сильно отличаются от истинных расчётных значений. Да и расчёт совсем не гибкий...

Я бы переписал чуть иначе.
Сначала надо придумать график и объявить его в самом начале кода в виде констант:

#define RPM_700 700 // Первая точка у нас на 700 об/мин
#define ANGLE_700 0
#define RPM_1000 1000
#define ANGLE_1000 22 // богомерзкий float умножаем на 10, пусть пока побудет целочисленным, а так это 2,2 градуса
#define RPM_2000 2000
#define ANGLE_2000 150
#define RPM_3000 3000
#define ANGLE_3000 251
#define RPM_4000 4000
#define ANGLE_4000 337

Вот мы получили график из 5 точек, соответствующий комментариям (не фактическим формулам!)
Так как графики между точками линейные, то вместо диких вычислений с плавающей точкой, волшебными коэффициентами и магическими слагаемыми можно взять более красивую функцию экстраполяции (map), а для наглядности и простоты добавления точек использовать switch case:


// расчёт угла по таблице из 5 точек с возможностью расширения до 60
float get_angle (unsigned int rpms) { // функция расчёта угла. Возвращает число с плавающей точкой, в качестве входного параметра принимает целочисленное значение оборотов в минуту
byte tempRPM = rpms / 100; // Делим обороты на 100, чтобы не расписывать варианты для каждого значения


switch (tempRPM) {
int tempDEG; // временная переменная, чтобы не трогать float
CASE 1:
CASE 2:
CASE 3:
CASE 4:
CASE 5:
CASE 6:
tempDEG = ANGLE_700; // вот мы поставили для первых 699 об/мин нулевой угол
break; // Не забываем ставить break там, где нужно прекратить проверку, если найдено сов падение


CASE 7:
CASE 8:
CASE 9:
tempDEG = map(rpm, RPM_700, RPM_1000, ANGLE_700, ANGLE_1000); // Вот пример использования функции. Приводим положение текущего значения оборотов в минуту в заданном диапазоне 700...1000 к соответствующей точке графика в диапазоне 0...22
break; // Не забываем ставить break!


CASE 10:
<...> // мне лень выписывать все строки от 10 до 19, да и пост слишком уж длинным получается, но они должны быть!
CASE 19:
tempDEG = map(rpm, RPM_1000, RPM_2000, ANGLE_1000, ANGLE_2000);
break;


CASE 20:
<...>
CASE 29:
tempDEG = map(rpm, RPM_2000, RPM_3000, ANGLE_2000, ANGLE_3000);
break;


CASE 30:
<...>
CASE 39:
tempDEG = map(rpm, RPM_3000, RPM_4000, ANGLE_3000, ANGLE_4000);
break;


CASE 40:
<...>
CASE 59:
tempDEG = ANGLE_4000; // А тут усреднение уже не нужно, тут полка угла.
break;


default:
tempDEG = 0; // По дефолту угол 0, если будет какое-то непредвиденное значение (например, 7000 RPM, или кто-то тоже поленится и не напишет CASE 25:, то при 2500 RPM тоже :-))
break;
}


return float(tempDEG) / 10; // и только сейчас переводим результат в число с плавающей точкой, делим на 10 и возвращаем в место вызова функции, хотя подозреваю, что оно нафиг не надо, т.к. в других местах тоже можно переписать под целые числа.
}

Этот кусок можешь вставить в конец кода.

А всю магию можно заменить на одну строчку:
ignitionDegree = get_angle(rpm);

Это можно написать ещё красивее, но мне лень. :-)

Peacedeath подкрался незаметно, но слышен был издалека

Подправил шрифт в комментариях к коду, для лучшей читабельности. BuffoG

Artegro's picture

вариант с map куда симпатичнее, но тут сразу возникает вопрос а не проще обойтись теми же 5 if else if меж кнтрольных точек, чем городить 40 кейсов ?
#define RPM_700 700 // Первая точка у нас на 700 об/мин
#define ANGLE_700 0
#define RPM_1000 1000
#define ANGLE_1000 22 // богомерзкий float умножаем на 10, пусть пока побудет целочисленным, а так это 2,2 градуса
#define RPM_2000 2000
#define ANGLE_2000 150
#define RPM_3000 3000
#define ANGLE_3000 251
#define RPM_4000 4000
#define ANGLE_4000 337

// это из тела программы в замен кривых расчетов .

if (rpm >= 0 && rpm <= 700) {
oldtime = micros();
ignitionFlag = true;
return;
}
else if (rpm >= 700 && rpm <= 1000) { // 0 - 2.2
ignitionDegree = (map(rpm, RPM_700, RPM_1000, ANGLE_700, ANGLE_1000))/10;
}
else if (rpm > 1000 && rpm <= 2000) { // 2.2 - 15
ignitionDegree = (map(rpm, RPM_1000, RPM_2000, ANGLE_1000, ANGLE_2000))/10;
}
else if (rpm > 2000 && rpm <= 3000) { // 15 - 25.1
ignitionDegree = (map(rpm, RPM_2000, RPM_3000, ANGLE_2000, ANGLE_3000))/10;
}
else if (rpm > 3000 && rpm <= 4000) {// 25.1 - 33.7
ignitionDegree = (map(rpm, RPM_3000, RPM_4000, ANGLE_3000, ANGLE_4000))/10;
}
else if (rpm > 4000) {
ignitionDegree = 33.7;
}

или в замен этого всего просто сделать такой
тут уж не надо констант и выборов .. а обработку ДАД сделать тем же мап .. допустим зашить ему изменение от 0 до -20 при изменении показания с датчика от 0 до 450мВ

if (rpm >= 0 && rpm <= 700) {
oldtime = micros();
ignitionFlag = true;
return;
}
else if (rpm >= 700 && rpm <= 5000) { // 0 - 2.2
rpm = rpm/100;
ignitionDegree = ((-0.02)*rpm*rpm)+1.96*rpm + (-15);
}

else if (rpm > 5000) {
ignitionDegree = 33.7;

PCDeath's picture

Без полного кода править его куски - такое себе удовольствие. Ещё и в древовидной структуре, где ни фига не понятно.

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

Но вообще для совместной разработки принято использовать gitHub :-)

Peacedeath подкрался незаметно, но слышен был издалека

PCDeath's picture

Скинь текст шестерёнкой, погляжу и покажу.

Увы, у меня несколько иная цель. Мне нужен в электронный тахометр сигнал системы зажигания, но гальванически развязанный от катушки, чтобы не спалить МК, и имеющий чёткие фронты без дребезга. Пока экспериментирую с оптопарой.

Peacedeath подкрался незаметно, но слышен был издалека

Artegro's picture

а если брать сигнал с датчика хола или оптики , который идет на комутатор ?

Esperoty's picture

Отправил шестерней, потом можно сюда запостить итоговый вариант, чтобы при необходимости каждый сам мог просто углы свои проставить

Artegro's picture

метал корпус с заземлением?

Artegro's picture

а как график выглядет то есть формула в визуале его представить?

PCDeath's picture

Дык Excel - наше всё.
Держи график по твоим формулам.

Quote:
if (rpm >= 700 && rpm <= 1000) { // 0 - 2.2
ignitionDegree = 0.007 * rpm + (-5.133);
}
if (rpm >= 1000 && rpm <= 2000) { // 2.2 - 15
ignitionDegree = 0.013 * rpm + (-10.600);
}

Истинны оба условия. На 1000 об/мин угол резко скакнёт с 1,87 до 2,4

И комменты неправильные.
1000 * 0,007 - 5,133 = 7 - 5,133 = 1,867, а никак не 2,2.
1000 * 0,013 - 10,6 = 13 - 10,6 = 2,4, а не 2,2
Peacedeath подкрался незаметно, но слышен был издалека

Artegro's picture

ох с таким графиком все должно вообще в одной строчке считаться линейно .. он почти прямой..

формулы не мои , это оригинал от разработчиков ))

Artegro's picture

почитал немного даташит на платку.. можно к ней прикрутить аналоговый датчик ДАД , например такой https://aliexpress.ru/item/4000274503044.html?spm=a2g0o.productlist.0.0....

и запилить в расчет от его показаний уменьшение оперяжения например от 0 до 25 градусов , по идеи это делается парой строчек

PCDeath's picture

Ну не парой, не парой...
Тут уже получается трёхмерная карта, т.к. УОЗ начинает зависеть не только от оборотов, но и от разрежения.
Но если усреднить карту (сделать 5 точек по оборотам, 5 - по давлению, итого 25), то реально и в Tiny впихнуть.

Однако ДАД на нашем оппозите имеет смысл при монокарбе. Иначе нужно вешать либо два ДАД, либо смириться с некоторым несоответствием карты из-за разницы разрежения во впускных трактах разных цилиндров.

Peacedeath подкрался незаметно, но слышен был издалека

Artegro's picture

еще вопрос почему не считать все в милисекундах а не в микросекондах.. сорян за тупость с ардуино знаком я только вот пару часов сегодня.. или процессорное время единица в микроСек ?

PCDeath's picture

Потому что при 6000 об/мин один оборот происходит за 1/6000 минуты, или 1/100 секунды, или 10 мс.
Таким образом, на одну миллисекунду приходится 36 градусов вращения.
Получается очень дискретное опережение - либо 0 градусов, либо 36...

Peacedeath подкрался незаметно, но слышен был издалека

РЕКЛАМА's picture

А нельзя расчет кривой прямо в скетче сделать чтоб высчитывался?
Ну типа подставляем в нужные места значения желаемого опережения на нужном промежутке и дальше оно уже само компилируется.
?
Чтоб не воландаться каждый раз с формулами?

Я так-то начинающий ардуинщик, пока только автоматику на автоматические ворота себе написал, и то из кусков других скетчей..

PCDeath's picture

Можно, конечно. Но чем больше точек, тем больше вес программы.
Чтобы составить таблицу, нужно определённое количество точек.

При самом оптимизированном размещении (3 байта на точку - 2 на об/мин, 1 - на угол опережения) на таблицу в 100 точек понадобится отвести 300 байт.
В 1000 точек - 3000 байт.
А то, что между точками, всё равно придётся высчитывать по формулам, ибо в диапазоне от 600 до 6000 об/мин - 5400 точек, и это уже почти 16 КБайт, что явно не влезет в Тини, это объём уже для Меги 32 и дальше.

Или я неправильно понял твою идею?
Если идея в том, чтобы задать пары "Обороты - угол" и ввести единую функцию для их расчёта, то тут примерно это и сделано. Только сделано коряво - объявлено "магическими числами" прямо в коде, а не вынесено в понятные человекочитаемые константы или переменные.

Peacedeath подкрался незаметно, но слышен был издалека

РЕКЛАМА's picture

Да, я про второй вариант имел в виду. Чтоб не на сайте готовить скетч, а прямо перед прошивкой выставил нужные цифры прямо в тексте скетча и всё.

PCDeath's picture

Чуть выше написал пример, как это можно написать более наглядно, масштабируемо и менее ресурсоёмко.

Peacedeath подкрался незаметно, но слышен был издалека

Artegro's picture

вывел формулу по которой изменяется график от 1000 до 4000 y=-0,0000011*x2+0,0162*x-12,8

если перед началом действий делить обороты на 100 по формула будет y=−0.02x2+1.96x−15 по трудозатратам хз как проще считать... но в это варианте получается перевернутая парабола с пиком на 4900 оборотов график начинается примерно с 850 оторотов

PCDeath's picture

X = обороты, Y = угол, правильно понимаю?
Странные какие-то формулы, если честно. Но проверю. Откуда эти графики взял, если не секрет?

Вечером буду в жилище, нарисую график в Excel. Или сам скинь, полюбуюсь.

Оптимизировать будем потом, сначала надо добиться корректных расчётов. :-)

Peacedeath подкрался незаметно, но слышен был издалека

Artegro's picture

все верно, y- угол x - обороты.
сам график тупо брал по контрольным точкам от этого зажигания
вот на этом сайте подобрал формулу в онлайн расчетах
http://mathhelpplanet.com/static.php?p=onlayn-mnk-i-regressionniy-analiz

потом в экселе правил коэфиценты до приемлемых графиков.
файлик тут https://drive.google.com/file/d/1HN_ZuDV-9Lb1h3CIE2CUgWiGXlH9z2FA/view?u...
можно пользовать по ссылке его

PCDeath's picture

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

Peacedeath подкрался незаметно, но слышен был издалека

Artegro's picture

докинул обработку MAP по спеки МАР выходное напряжение от 0 до 4.5В
но это если ардуино понимает сигнал с миливольтах
по спеки платы назначил аналоговый вход
pinMode(2, INPUT);

void countIgnitionTime() {
ignitionDegree =ignitionDegree + (map(analogRead(1), 450, 0, 0, -200) / 10);
nextIgnition = (500000 * (360 - ignitionDegree)) / (3 * rpm) + VMTtime;
ignitionFlagWithOffset = true;
}

PCDeath's picture

Вот тут совсем не понял...
Сколько бит АЦП у платы? 10?
Диапазон АЦП - 0...5 вольт?
Тогда у тебя при 0 вольтах на аналоговом входе функция analogRead вернёт значение 0, а при 5 - 1023.
Какое напряжение на выходе датчика при атмосферном давлении и какое - при максимальном разрежении?
На какое значение ты хочешь корректировать УОЗ при атмосферном давлении, и на какое - при максимальном разрежении?

p.s. менять глобальные переменные внутри вызываемой функции (не loop) - моветон. При отладке придётся бегать по всем функциям и вспоминать, где какая переменная меняется. Глобальные переменные лучше менять только внутри основной (void loop() в случае Ардуино)
Peacedeath подкрался незаметно, но слышен был издалека

Artegro's picture

плата https://www.sgbotic.com/products/datasheets/sensors/02976-datasheet.pdf
предположительно надо брать от -100 до 0 модификация XGZP6847100KPGN
исходя из получается что берем значение от 0.5 до 4.5В изменяется при -100 до 0 кРа в реале подозреваю что значение будет меняться меньше .. это придется проверять опытным путем на моторе.
возможно надо просто записывать максимальное и минимальное значение в переменные во всем рабочем цикле и использовать уже их , тогда нам не важно какие именно будут значения на самом МАР

пришло вот такое в голову
long int LoadMax = 10;
long int LoadMin =9;
long int LoadD;

loop
if (ignitionDegree > 0) {
LoadD = analogRead(1);
if (LoadD > LoadMax) {
LoadMax = LoadD;
}
else if (LoadD < LoadMin) {
LoadMin = LoadD;
}
ignitionDegree =ignitionDegree + (map(LoadD, LoadMin, LoadMax, 0, -200) / 10);
countIgnitionTime();
}

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

BuffoG's picture

А почему ты берешь именно такой МАР? Этот МАР надо еще как-то вкорячить во впуск, почему не взять готовый МАР от авто?

Как вариант
https://www.avtoall.ru/datchik_absolyutnogo_davleniya_vozduha_gaz_uaz_um...
http://clubturbo.ru/market/elektronika/datchik_absolyutnogo_davleniya/da...
У последнего даже график работы есть

___________________________________________________________________
"Человека можно уничтожить, но его нельзя победить" (Э. Хемингуэй)

PCDeath's picture

Что-то мы с тобой тему-то подзасрали, и начинаем лезть не в те дебри.
Давай сначала человечьим языком опишем, что мы хотим получить, прежде чем код трогать. Потому что сейчас я вижу:


// Объявили 3 глобальных переменных, зачем-то long, занимающий 4 байта, хотя двухбайтового беззнакового uint16 вполне хватило бы
long int LoadMax = 10;
long int LoadMin =9;
long int LoadD;

// циклически выполняющаяся функция
loop
if (ignitionDegree > 0) { // если УОЗ больше нуля, то
LoadD = analogRead(1); // читаем аналоговый вход (MAP)
if (LoadD > LoadMax) { // Если прочитанное значение больше текущего значения в переменной LoadMax
LoadMax = LoadD; // Устанавливаем значение LoadMax равное считанному значению.
}
else if (LoadD < LoadMin) { // иначе если прочитанное значение меньше LoadMin
LoadMin = LoadD; // Устанавливаем значение LoadMin равное считанному значению.
}
ignitionDegree =ignitionDegree + (map(LoadD, LoadMin, LoadMax, 0, -200) / 10); // прибавляем к переменной ignitionDegree значение (экстраполяция переменной LoadD в диапазоне от LoadMin до LoadMax на диапазон от 0 до -200 делённое на 10)
countIgnitionTime(); / вызываем некую функцию расчёта времени
}

В этом случае у тебя получится следующее:
При включении зажигания:
- На датчике атмосферное давление, на аналоговом входе 4,5V (analogRead(1) вернёт 920)
- ignitionDegree = 0
- Переменные LoadMin и LoadMax имеют значение 9 и 10 соответственно, т.к. ignitionDegree = 0

При запуске двигателя и ХХ 600 об/мин:
- На датчике появилось некое разрежение, условно -50 КПа, на аналоговом входе 2,5V (analogRead(1) вернёт 511)
- ignitionDegree = 0
- Переменные LoadMin и LoadMax имеют значение 9 и 10 соответственно, т.к. ignitionDegree = 0

При подъёме до 1000 об/мин:
- На датчике уменьшилось разрежение до -45 КПа, на аналоговом входе 2,7V
- Функция analogRead возвращает значение 552
- LoadD = 552
- ignitionDegree = 2,2
- Переменная LoadMin имеет значение 9, LoadMax принимает значение 552
- функция экстраполяции map(LoadD, LoadMin, LoadMax, 0, -200) возвращает значение -200, т.к. LoadD = LoadMax
- Переменная ignitionDegree принимает значение 2,2 + (- 200 / 10) = -17,8
- Мотор глохнет

Тебе точно нужен такой угол опережения?
Распиши сначала, какой именно алгоритм обработки тебе нужен. "Если - то - иначе". Сразу писать код тоже можно, конечно, но тогда хотя бы комментируй его, иначе через пару недель сам не вспомнишь, что и для чего.

Peacedeath подкрался незаметно, но слышен был издалека

Artegro's picture

первоначальные значения при назначении переменных пока стоят от балды , чисто для понимания,
по идеи можно прям со старта в setup присваивать loadMax значение AnalogRead(1) а LoadMin = LoadMax-10
тогда у нас максимальное разряжение будет писаться по мере работы двигателя, единственный момент что такая само установка покажет при сбросе газа например с 5000 оборотом и , не уплывет ли весь график после этого..

п.с.
и цифры например в -200 и 0 , их спокойно можно подвинуть например (100 , -200 )взята то же чисто для понимания алгоритма ,
возможно нам и не надо такой сложной системы и мы берем один раз в сетап присваиваем
loadMax = AnalogRead(1);
LoadMin = 0;
и может этого достаточно , так как атмосферного давления во впуске мы не получим, только приближение к нему при резко открытом газе.

почему беру именно этот дадчик , он дешев на али что то по 300р .. . можно и дадчик от газели прилепить... в этом то вроде проблем нет.

ссылка на скетч
как раз с этими правками
https://drive.google.com/file/d/1rRTP74p7kGGNRCdIZ0IxXFWP1vKnh5OF/view?u...

BuffoG's picture

Выскажусь немного за МАР - при проектировании ФУОЗ надо отталкиваться от максимальной надежности, унифицированности и
доступности запасных частей в случае поломки (т.е. можно купить в любом автомаге). Датчик с Али хоть и дешев, но заказа с али еще надо дождаться, датчик выполнен в "бескорпусном" исполнении, нужно придумывать переходную плату под типовой водонепроницаемый разъем, корпус. Готовые автошные хоть и дороже, но уже лишены всех перечисленных недостатков.
___________________________________________________________________
"Человека можно уничтожить, но его нельзя победить" (Э. Хемингуэй)

Artegro's picture

Добавил скетч без обработки мар, с таблицей констант в которой можно выставлять точки графика в самом скече
https://drive.google.com/file/d/1-ncc-kpv4j7sMXa-U6K8jeBgD-EYJGkQ/view?u...

PCDeath's picture

Вот этот же код, только разобранный по косточкам и с моими комментариями.

Работать будет даже с "магическими числами".
Но если ты собираешься его дорабатывать дальше - запихивать работу с MAP и вторым выходом, то его стоит рефакторить, ибо есть неиспользуемые переменные, переменные с непонятным принципом выбора типа данных и куски, где нет приведения данных к нужному типу, из-за чего, например, на 1200 RPM возникает погрешность - вместо расчётного угла 4,76 фактическое опережение будет от 4 до 5,1 градуса. Всё это затрудняет редактирование и увеличивает затраты времени и алкоголя на доработку, снижая прогнозируемость поведения.

Плюс если выключить зажигание на рабочем двигателе (щёлкнуть ДвигСтоп), а потом включить обратно, есть неиллюзорная вероятность пука в карбюраторы (см.строку 174). Но в общем и целом код работоспособен.

Peacedeath подкрался незаметно, но слышен был издалека

Esperoty's picture

else if имеет смысл менять на case ? С твоими комментами перенес с использованием case (обновил файл по ссылке, первый был косячный)
https://drive.google.com/file/d/1pNQQIaCo9AkcKGHd8h8d4N3VcSqo8uAc/view?u...
Если правильно понял. По идее в самом начале достаточно только углы свои подставлять, больше ничего менять не надо.

Вот картинка, кстати, с таблицей про нагрузку, обороты и опережение:
https://drive.google.com/file/d/1huxCUYirpKRp0JddKR4rjXoWQLrNVisB/view?u...

PCDeath's picture

Имеет смысл оценить размер скомпилированного кода в одном и в другом варианте,
Плюс в обоих вариантах стоит использовать временные переменные и однократный вызов функции map с передачей в неё этих переменных, чтобы не раздувать код - там вроде всего 8 кБайт в контроллере?

Плюс там есть зайчатки дебаггинга в виде вывода в serial значения оборотов в минуту.
Это дело хорошее, и его стоит продолжить, потому что можно, конечно, и мысленный эксперимент провести, как я сделал для трёх оборотов коленвала сферического двигателя в вакууме, но если прикручивать свистелки типа MAP-сенсора, то намного логичнее на стенде читать логи работы ФУОЗ в консоли, чем в сотый раз перечитывать в гараже прошивку и думать, почему мотоцикл начинает детонировать, стоит дать чуть нагрузки.

А вот таблица крайне спорная.
Не уверен, что её можно применить к нашим оппозитам. 20,7 градусов опережения на 600 об/мин???

Peacedeath подкрался незаметно, но слышен был издалека

Artegro's picture

Вот это Элиас огромное спасибо, да надо брать пиво и разбираться в коде и алгоритме по твоим комментариям .
В свое оправдание могу сказать что программировать для ардуино я не умею, ни синтаксиса, ни правил не знаю, правил скеч от блогеров опираясь на свои скудные знания паскаля и т.д. потому прошу не пинать. )) Пока время нет почитать методички по программированию на ардуино.... а мысли что возникают вечером , если не записать то забуду, и потом вспоминай какое изящное пришло решение с обработкой МАР сенсора например ))

П.С
почему ты пишешь : (map(rpm, RPM_700, RPM_1000, ANGLE_700, ANGLE_1000)) / 10; // устанавливаем float угол в пределах от 0 до 2 с шагом 1 градус (потому что оперируем не плавающей точкой, а целочисленными константами)

получается , что функция мар возвращает целочисленное число и её нельзя поделить с остатком?
тогда получается строка должна быть такой:
ignitionDegree = map(rpm, RPM_1000, RPM_2000, ANGLE_1000, ANGLE_2000);
ignitionDegree = ignitionDegree / 10;
?

так же в принципе все расчеты можно построить на значениях углов * 10 "как в объявлении констант" чтоб не пользовать запятых.

PCDeath's picture

Да пожалуйста. Всё равно не спалось. :-)

Оправдания не нужно - я ж понимаю, что это левый код, написанный кем-то в Интернетах, и он почему-то работает, но хочется лучше.
Начало положено. Теперь он хотя бы понятный.

Quote:
получается , что функция мар возвращает целочисленное число и её нельзя поделить с остатком?

Да, функция map принимает на вход целые числа и возвращает целочисленное значение. Если она вернёт 47, то поделив это число на целочисленное 10, мы получим... Нет, не 4,7 и даже не 5. Мы получим 4. Дробная часть будет отброшена.
Поэтому целочисленное 47 сначала надо привести к типу с плавающей точкой, чтобы поделить его на 10 и получить дробное значение.

Quote:
тогда получается строка должна быть такой:
ignitionDegree = map(rpm, RPM_1000, RPM_2000, ANGLE_1000, ANGLE_2000);
ignitionDegree = ignitionDegree / 10;
?

Можно и так. Но здесь у тебя получается целых две операции, в которых участвует переменная с плавающей точкой.

Правильный путь - это

Quote:
все расчеты можно построить на значениях углов * 10 "как в объявлении констант" чтоб не пользовать запятых.

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

Peacedeath подкрался незаметно, но слышен был издалека

Artegro's picture

Если мы считает угол так , угол*10
ignitionDegree = map(rpm, RPM_1000, RPM_2000, ANGLE_1000, ANGLE_2000);

то функция расчета времени искры будет такой:

void countIgnitionTime() { // Функция расчёта времени для следующего момента зажигания
nextIgnition = VMTtime + diffTime - (diffTime/360*ignitionDegree/10); // формула времявмт +время оборота- время оборота деленое на 360 градусов(нашли время одного градуса) умножили на необходимое количество градусов и разделили на 10 (так как градусы получаем в *10 состоянии)
ignitionFlagWithOffset = true;
}

немного причесал скеч с учетом правок и замечаний Элиоса , так же добавил условие первого запуска программы с бездействием до первого полного оборота по втм , так же в новый код сделал обработку МАР, расчеты угла сделал до 5000 оборотов , графики зашил пока для м72 лежит тут версия с МАР и без

User login