Требуется помощь в написании кода

Всем доброго времени суток!
Мне нужен скетч
Код простенький, два датчика скорости, четыре условия.
Логику работы понимаю, а написать не могу, нужно в этом деле практически заниматься, а у меня по некоторым причинам нет этой возможности, по крайней мере сейчас.
Так вот к сути:
Заказал для мотоцикла электронную приборную панель, на ней есть индикатор передачи КПП, но физического датчика нет и установить его без разборки ДВС не получится, даже если придумаю как это реализовать. Так вот я решил это реализовать с помощью Ардуино. Алгоритм прост, есть два индуктивных датчика, один на коленвале (обороты двигателя) второй на вторичном валу (обороты ведущей звёзды) есть передаточные числа КПП. Под эти данные нужен скетч.

//
RPM1- (переменная) обороты двигателя.

RPM2 – (переменная) обороты вторичного вала.

K – (постоянная величина) передаточное число коленчатого вала к первичному =2,57142857

K1 - (постоянная величина) передаточное число первой передачи = 3,17

K2 – (постоянная величина) передаточное число второй передачи = 1,81

К3 – (постоянная величина) передаточное число 3 передачи = 1,26

К3 – (постоянная величина) передаточное число 4 передачи = 1,1

Если
RPM1/K/RPM2=K1
то высокий сигнал выход на пин 1

Если
RPM1/K/RPM2=К2
то высокий сигнал выход на пин 2

Если
RPM1/K/RPM2=К3
то высокий сигнал выход на пин 3

Если
RPM1/K/RPM2=К4
то высокий сигнал выход на пин 4

Иначе низкий сигнал на всех

(Номера пинов указаны образно)

//

Помогите пожалуйста решить вопрос.

1 лайк

Это уже физически реализовано?

ваще без проблем)

Спойлер

Мы будем использовать два индуктивных датчика: один на коленвале (дающий импульсы, пропорциональные оборотам коленвала), второй на вторичном валу (обороты ведущей звезды).
Передаточные числа КПП известны для каждой передачи.
Идея: вычисляем соотношение частот импульсов с датчика коленвала и датчика вторичного вала.
Это соотношение будет равно передаточному числу передачи, умноженному на некоторый постоянный коэффициент (связанный с количеством зубьев, на которых установлены датчики, и передаточным числом главной передачи и т.п.).
Однако, чтобы не зависеть от абсолютных значений частот, мы можем использовать отношение частот.
Пусть:
f_engine - частота импульсов с датчика коленвала (обороты двигателя)
f_wheel - частота импульсов с датчика вторичного вала (обороты ведущей звезды)
Передаточное число на передаче i: gear_ratio[i] = (f_engine / f_wheel) * k, где k - постоянный коэффициент, который нужно определить.
Но на самом деле, если мы знаем передаточные числа КПП и главной передачи, то можем вычислить ожидаемые отношения.
Однако, чтобы избежать необходимости знать точный коэффициент k, можно его исключить, сравнивая отношение частот с заранее известными передаточными числами.
Допустим, у нас есть массив передаточных чисел для каждой передачи (включая главную передачу и цепь/ремень, если нужно) - но точнее, нам нужно общее передаточное число от коленвала до ведущей звезды для каждой передачи.
Но на самом деле, мы можем вычислить коэффициент k, если знаем, что на определенной передаче (например, на первой) передаточное число известно.
Однако, проще сделать так: мы знаем, что для каждой передачи i должно выполняться:
f_engine / f_wheel = gear_ratio_total[i] (если датчики установлены так, что выдают одинаковое количество импульсов на оборот)
Но на практике датчики могут иметь разное количество импульсов на оборот. Поэтому введем:
pulses_per_rev_engine - количество импульсов на один оборот коленвала
pulses_per_rev_wheel - количество импульсов на один оборот вторичного вала
Тогда:
f_engine = (rpm_engine * pulses_per_rev_engine) / 60
f_wheel = (rpm_wheel * pulses_per_rev_wheel) / 60
Отношение:
(f_engine / f_wheel) = (rpm_engine / rpm_wheel) * (pulses_per_rev_engine / pulses_per_rev_wheel)
А rpm_engine / rpm_wheel - это общее передаточное число от коленвала до вторичного вала (включая главную передачу) для данной передачи.
Пусть общее передаточное число для передачи i (от коленвала до вторичного вала) равно gear_ratio_total[i]. Тогда:
(f_engine / f_wheel) = gear_ratio_total[i] * (pulses_per_rev_engine / pulses_per_rev_wheel)
Обозначим constant = pulses_per_rev_engine / pulses_per_rev_wheel
Тогда для каждой передачи i:
gear_ratio_total[i] = (f_engine / f_wheel) / constant
Но мы не знаем constant? Мы можем его вычислить, если знаем передаточное число для одной передачи, но мы знаем передаточные числа КПП и главной передачи.
Однако, чтобы избежать зависимости от constant, можно поступить иначе: мы можем измерить отношение f_engine / f_wheel для каждой передачи и сравнить с ожидаемым относительным значением.
Но на самом деле, мы можем вычислить constant, если знаем, что на какой-то передаче (например, на первой) передаточное число известно.
Допустим, у нас есть массив передаточных чисел КПП (без главной) и отдельно передаточное число главной передачи. Тогда общее передаточное число для передачи i:
gear_ratio_total[i] = gear_ratio_gearbox[i] * final_drive_ratio
Но если датчик на вторичном валу стоит после главной передачи, то тогда нам не нужно учитывать главную передачу?
Уточнение: вторичный вал - это ведущая звезда? Если да, то тогда передаточное число от коленвала до ведущей звезды = передаточное число КПП * передаточное число главной передачи.
Однако, если датчик на вторичном валу установлен на ведущей звезде, то он вращается с скоростью ведущей звезды. Тогда общее передаточное число от коленвала до ведущей звезды = gear_ratio_gearbox[i] * final_drive_ratio.
Но если датчик на вторичном валу установлен до главной передачи, то тогда главная передача не учитывается в датчике, и нам нужно это учесть.
В данном случае, по условию: датчик на вторичном валу (обороты ведущей звезды). Значит, он вращается с скоростью ведущей звезды. Тогда общее передаточное число от коленвала до ведущей звезды = gear_ratio_gearbox[i] * final_drive_ratio.
Теперь, если мы знаем передаточные числа КПП и главной передачи, то мы знаем gear_ratio_total[i] для каждой передачи.
Тогда:
(f_engine / f_wheel) = gear_ratio_total[i] * (pulses_per_rev_engine / pulses_per_rev_wheel)
Обозначим K = constant = pulses_per_rev_engine / pulses_per_rev_wheel
Тогда для каждой передачи i:
gear_ratio_total[i] * K = (f_engine / f_wheel)
Мы не знаем K? Но мы можем ее вычислить, если знаем передаточное число для какой-то передачи и измерили отношение частот на этой передаче.
Однако, мы хотим определить текущую передачу. Мы можем вычислить измеренное передаточное число (без K) как:
measured_ratio = f_engine / f_wheel
Тогда истинное передаточное число будет measured_ratio / K.
Но мы не знаем K. Поэтому нам нужно откалибровать K. Например, мы можем проехаться на первой передаче (которая имеет самое большое передаточное число) и запомнить measured_ratio. Тогда K = measured_ratio / gear_ratio_total[1].
Однако, это требует калибровки. Но можно обойтись без калибровки, если датчики имеют одинаковое количество импульсов на оборот. Тогда K=1.
Но в общем случае, нам нужно знать pulses_per_rev_engine и pulses_per_rev_wheel.
Допустим, мы знаем эти значения. Тогда K = pulses_per_rev_engine / pulses_per_rev_wheel.
Тогда мы можем вычислить текущее общее передаточное число:
current_ratio = (f_engine / f_wheel) / K
Затем мы сравниваем current_ratio с известными gear_ratio_total[i] для каждой передачи и выбираем ту передачу, для которой разница минимальна.
Учтем, что при работе возможны небольшие отклонения, поэтому нужно сравнивать с допуском.
Также учтем, что на нейтральной передаче (если она есть) двигатель может работать, а мотоцикл стоять. Тогда f_wheel будет близко к нулю, а f_engine - нет. Поэтому нужно обрабатывать нейтраль отдельно.
Также возможна ситуация, когда мотоцикл стоит, а двигатель работает - тогда f_wheel=0, а f_engine>0 - это нейтраль или выжатое сцепление? Но по условию мы не можем определить выжатое сцепление, поэтому будем считать, что если мотоцикк стоит, то мы не можем определить передачу (кроме нейтрали).
Однако, если мы движемся, то мы можем определить передачу.
План:

  1. Определяем частоты f_engine и f_wheel.
    Для этого можно измерять период между импульсами или подсчитывать количество импульсов за фиксированный интервал времени.
  2. Вычисляем current_ratio = (f_engine / f_wheel) / K, где K = (pulses_per_rev_engine / pulses_per_rev_wheel)
  3. Сравниваем current_ratio с каждым из gear_ratio_total[i] (для i от 1 до N) и находим передачу, для которой разница минимальна (в пределах допуска).
  4. Если f_wheel очень мала (ниже некоторого порога, например, 0.1 Гц) и f_engine выше порога, то считаем, что это нейтраль (или сцепление выжато, но мы не можем отличить, поэтому будем считать нейтралью).
  5. Если current_ratio не попадает ни в один допуск, то оставляем предыдущую передачу или показываем ошибку.
    Однако, есть нюансы: при движении накатом (с отпущенным сцеплением) передача остается включенной, но если выжать сцепление, то f_engine упадет (так как двигатель на холостых), а f_wheel будет определяться скоростью движения. Тогда current_ratio изменится. Поэтому, возможно, нужно учитывать, что сцепление выжато? Но по условию мы не имеем датчика сцепления.
    Поэтому, возможно, стоит ввести таймер: если в течение некоторого времени current_ratio не соответствует ни одной передаче, то показываем нейтраль (или предыдущую передачу?).
    Но лучше, если мы будем показывать передачу только тогда, когда current_ratio стабильно попадает в допуск для одной из передач.
    Реализация на Ардуино:
    Будем использовать два цифровых входа для датчиков. Датчики индуктивные, поэтому возможно, потребуется подтяжка и фильтрация.
    Для измерения частоты можно использовать подсчет импульсов за фиксированный интервал времени (например, 100 мс).
    Однако, чем короче интервал, тем менее точны измерения на низких оборотах. Но для мотоцикла низкие обороты - это холостой ход (около 1000 об/мин) и выше.
    Допустим, pulses_per_rev_engine = 1 (один импульс на оборот коленвала) и pulses_per_rev_wheel = 1 (один импульс на оборот ведущей звезды). Тогда K=1.
    Тогда current_ratio = f_engine / f_wheel.
    Примерные передаточные числа для мотоцикла (возьмем для примера):
    gear_ratio_gearbox[1] = 3.0
    gear_ratio_gearbox[2] = 2.0
    gear_ratio_gearbox[3] = 1.5
    gear_ratio_gearbox[4] = 1.2
    gear_ratio_gearbox[5] = 1.0
    gear_ratio_gearbox[6] = 0.8
    final_drive_ratio = 3.0
    Тогда общее передаточное число для первой передачи: 3.0 * 3.0 = 9.0
    для второй: 2.0 * 3.0 = 6.0
    для третьей: 1.5 * 3.0 = 4.5
    и т.д.
    Допустим, мы измеряем f_engine и f_wheel.
    Пример: двигатель 3000 об/мин, ведущая звезда 3000/9 = 333.33 об/мин.
    Если pulses_per_rev_engine = 1, то f_engine = 3000/60 = 50 Hz.
    Если pulses_per_rev_wheel = 1, то f_wheel = 333.33/60 = 5.555 Hz.
    Тогда current_ratio = 50 / 5.555 = 9.0 → первая передача.
    Теперь, если мы не знаем pulses_per_rev, то нам нужно их задать.
    Предположим, что на коленвале датчик выдает 1 импульс на оборот, а на ведущей звезде - 1 импульс на оборот. Тогда K=1.
    Но если на коленвале датчик имеет 2 импульса на оборот, то f_engine будет 100 Hz, а current_ratio = 100/5.555 = 18, что не совпадает с 9. Поэтому важно знать pulses_per_rev.
    Значит, мы должны знать количество импульсов на оборот для каждого датчика.
    Пусть:
    pulses_per_rev_engine = PPR_ENG
    pulses_per_rev_wheel = PPR_WHEEL
    Тогда K = PPR_ENG / PPR_WHEEL
    В коде мы будем измерять количество импульсов за период T (например, 100 мс). Тогда:
    f_engine = (count_engine / T) / PPR_ENG [в оборотах в секунду?]
    Но нет, частота в Гц: f_engine = (count_engine / T) [Гц] - это количество импульсов в секунду.
    Тогда обороты двигателя в об/мин: rpm_engine = (f_engine * 60) / PPR_ENG
    Аналогично для f_wheel.
    Но нам не нужны абсолютные обороты, нам нужно отношение:
    current_ratio = (f_engine / f_wheel) * (PPR_WHEEL / PPR_ENG)
    потому что:
    f_engine = (импульсы двигателя в секунду)
    f_wheel = (импульсы ведущей звезды в секунду)
    Тогда: (f_engine / f_wheel) = (обороты двигателя * PPR_ENG) / (обороты ведущей звезды * PPR_WHEEL)
    А обороты двигателя / обороты ведущей звезды = gear_ratio_total[i]
    Поэтому: (f_engine / f_wheel) = gear_ratio_total[i] * (PPR_ENG / PPR_WHEEL)
    => gear_ratio_total[i] = (f_engine / f_wheel) * (PPR_WHEEL / PPR_ENG)
    Таким образом, current_ratio = (f_engine / f_wheel) * (PPR_WHEEL / PPR_ENG)
    и это должно быть равно gear_ratio_total[i] для передачи i.
    Поэтому в коде мы будем вычислять:
    current_ratio = (count_engine / count_wheel) * (PPR_WHEEL / PPR_ENG)
    потому что за время T: count_engine = f_engine * T, count_wheel = f_wheel * T, поэтому count_engine / count_wheel = f_engine / f_wheel.
    Но важно, чтобы count_wheel не был нулем. Поэтому нужно обрабатывать деление на ноль.
    Также, если count_wheel очень мал, то current_ratio будет большим, но это может быть из-за низкой скорости.
    Реализация:
    Определяем PPR_ENG и PPR_WHEEL как константы.
    Выбираем интервал измерения T (например, 100 мс).
    Используем два прерывания для подсчета импульсов с датчиков.
    В loop() каждые T миллисекунд считываем счетчики и сбрасываем их.
    Вычисляем current_ratio = (count_engine * PPR_WHEEL) / (count_wheel * PPR_ENG)
    Сравниваем current_ratio с массивом передаточных чисел gear_ratio_total[i] для i от 1 до 6 (например).
    Находим передачу, для которой разница между current_ratio и gear_ratio_total[i] минимальна (в пределах допуска, например, 5%).
    Если разница больше допуска для всех передач, то оставляем предыдущую передачу или показываем 0 (нейтраль).
    Также, если count_wheel == 0, то считаем, что мотоцикл стоит, и показываем нейтраль (или не меняем передачу, если уже была включена, но это небезопасно, поэтому лучше нейтраль).
    Но если count_wheel == 0 и count_engine > 0, то это нейтраль или сцепление выжато? Мы не знаем, но покажем нейтраль.
    Также, если count_engine == 0, то двигатель не работает - можно показывать нейтраль.
    Однако, при движении накатом (с отпущенным сцеплением) двигатель может работать на холостых, а count_engine будет небольшим. Поэтому нужно быть осторожным.
    Допуск нужно подобрать экспериментально.
    Также, чтобы избежать ложных срабатываний при низких оборотах, можно установить минимальное значение count_wheel, ниже которого определение передачи не происходит.
    Например, если count_wheel < 5 (за время T), то считаем, что скорость слишком низкая для точного определения.
    Аналогично для count_engine.
    Код:
    Константы:
    PPR_ENG = 1 (если один импульс на оборот коленвала)
    PPR_WHEEL = 1 (если один импульс на оборот ведущей звезды)
    T = 100 [мс]
    Массив передаточных чисел:
    float gear_ratio_total = {9.0, 6.0, 4.5, 3.6, 3.0, 2.4}; // для 6 передач
    Глобальные переменные:
    volatile unsigned int count_engine = 0;
    volatile unsigned int count_wheel = 0;
    Функции прерываний:
    void countEngine() { count_engine++; }
    void countWheel() { count_wheel++; }
    Setup:
    attachInterrupt(digitalPinToInterrupt(2), countEngine, RISING); // датчик двигателя на пине 2
    attachInterrupt(digitalPinToInterrupt(3), countWheel, RISING); // датчик колеса на пине 3
    Loop:
    every T milliseconds:
    noInterrupts();
    unsigned int current_count_engine = count_engine;
    unsigned int current_count_wheel = count_wheel;
    count_engine = 0;
    count_wheel = 0;
    interrupts();
    // Если двигатель не работает, то передача неизвестна - показываем нейтраль (0)
    if (current_count_engine == 0) {
    setGear(0);
    continue;
    }
    // Если ведущая звезда не вращается (мотоцикл стоит), то показываем нейтраль
    if (current_count_wheel == 0) {
    setGear(0);
    continue;
    }
    // Вычисляем current_ratio
    float current_ratio = (current_count_engine * (float)PPR_WHEEL) / (current_count_wheel * (float)PPR_ENG);
    // Ищем ближайшую передачу
    int current_gear = 0;
    float min_diff = 1000.0; // большое число
    for (int i = 0; i < 6; i++) {
    float diff = abs(current_ratio - gear_ratio_total[i]);
    if (diff < min_diff) {
    min_diff = diff;
    current_gear = i+1;
    }
    }
    // Проверяем, что минимальная разница в пределах допуска (например, 5%)
    float tolerance = gear_ratio_total[current_gear-1] * 0.05;
    if (min_diff > tolerance) {
    current_gear = 0; // не попадает в допуск - нейтраль
    }
    setGear(current_gear);
    Функция setGear() выводит передачу на дисплей или отправляет куда-то.
    Замечания:
  • Этот алгоритм может быть чувствителен к шумам и точности датчиков.
  • Нужно обеспечить, чтобы датчики давали четкие импульсы.
  • Возможно, потребуется фильтрация (аппаратная или программная) для исключения ложных срабатываний.
  • Интервал T не должен быть слишком коротким, чтобы на низких оборотах было достаточно импульсов, и не слишком длинным, чтобы быстро обновлять информацию.
    Также учтем, что при переключении передач возможны кратковременные рассогласования, поэтому можно ввести задержку перед определением передачи после изменения current_ratio.
    Но для простоты будем обновлять каждые T.
    Если мотоцикл движется накатом с выжатым сцеплением, то current_ratio будет неправильным, но мы будем считать, что передача не изменилась, пока current_ratio не стабилизируется для новой передачи (но при выжатом сцеплении передача осталась той же, но current_ratio будет большим, так как f_wheel определяется скоростью, а f_engine - холостыми оборотами). Поэтому в таком случае мы покажем нейтраль (так как current_ratio не будет соответствовать ни одной передаче).
    Это приемлемо, так как при выжатом сцеплении передача не engaged, и можно считать, что мы на нейтрали.
    Однако, если сцепление отпущено и передача engaged, то current_ratio должен соответствовать передаче.
    Поэтому в целом алгоритм должен работать.
    Давайте напишем код accordingly.
    Но note: в мотоцикле может быть нейтральная передача, которая не равна ни одной из передач. Поэтому мы ее определяем как 0.
    Также, если мотоцикк стоит на передаче с выжатым сцеплением, то current_count_wheel будет 0, а current_count_engine >0, поэтому мы покажем нейтраль. Это правильно, так как сцепление выжато, и передача не engaged.
    Однако, если мотоцикк стоит на передаче без выжатого сцепления (например, на светофоре), то двигатель заглохнет, и current_count_engine будет 0 → покажем нейтраль. Но это не совсем правильно, так как передача включена. Однако, если двигатель заглох, то perhaps неважно.
    Но если двигатель работает и мотоцикк стоит на передаче без выжатого сцепления, то двигатель заглохнет, так что это кратковременно.
    Поэтому в целом алгоритм приемлем.

Теперь код

Спойлер
// Пины для подключения датчиков
#define ENGINE_SENSOR_PIN 2  // Датчик коленвала
#define WHEEL_SENSOR_PIN 3   // Датчик вторичного вала

// Передаточные числа КПП (замените на свои значения)
float gearRatios[] = {3.0, 2.0, 1.5, 1.2, 1.0, 0.8}; // Пример для 6 передач
const int numGears = 6;

// Количество импульсов на оборот для каждого датчика
const int pulsesPerEngineRev = 1;  // Зависит от датчика
const int pulsesPerWheelRev = 1;   // Зависит от датчика

// Переменные для подсчета импульсов
volatile unsigned int enginePulses = 0;
volatile unsigned int wheelPulses = 0;

// Время последнего измерения
unsigned long lastTime = 0;
const unsigned long sampleTime = 100; // Время измерения в мс

void setup() {
  Serial.begin(9600);
  pinMode(ENGINE_SENSOR_PIN, INPUT);
  pinMode(WHEEL_SENSOR_PIN, INPUT);
  
  // Настройка прерываний для подсчета импульсов
  attachInterrupt(digitalPinToInterrupt(ENGINE_SENSOR_PIN), countEnginePulses, RISING);
  attachInterrupt(digitalPinToInterrupt(WHEEL_SENSOR_PIN), countWheelPulses, RISING);
}

void loop() {
  if (millis() - lastTime >= sampleTime) {
    // Отключаем прерывания для безопасного чтения значений
    noInterrupts();
    unsigned int currentEnginePulses = enginePulses;
    unsigned int currentWheelPulses = wheelPulses;
    enginePulses = 0;
    wheelPulses = 0;
    interrupts();

    // Рассчитываем частоты
    float engineFrequency = (1000.0 / sampleTime) * currentEnginePulses / pulsesPerEngineRev;
    float wheelFrequency = (1000.0 / sampleTime) * currentWheelPulses / pulsesPerWheelRev;

    // Определяем передачу
    int currentGear = determineGear(engineFrequency, wheelFrequency);
    
    Serial.print("Engine RPM: ");
    Serial.print(engineFrequency * 60); // Преобразование в RPM
    Serial.print(" | Wheel RPM: ");
    Serial.print(wheelFrequency * 60); // Преобразование в RPM
    Serial.print(" | Gear: ");
    Serial.println(currentGear);

    lastTime = millis();
  }
}

// Обработчики прерываний
void countEnginePulses() {
  enginePulses++;
}

void countWheelPulses() {
  wheelPulses++;
}

// Функция определения передачи
int determineGear(float engineFreq, float wheelFreq) {
  if (engineFreq < 0.1 || wheelFreq < 0.1) return 0; // Двигатель или вал остановлен
  
  float ratio = engineFreq / wheelFreq;
  
  // Поиск ближайшего передаточного числа
  float minDiff = 1000;
  int gear = 0;
  
  for (int i = 0; i < numGears; i++) {
    float diff = abs(ratio - gearRatios[i]);
    if (diff < minDiff) {
      minDiff = diff;
      gear = i + 1;
    }
  }
  
  // Проверка допустимой погрешности (10%)
  if (minDiff > gearRatios[gear-1] * 0.1) {
    return 0; // Нейтральная передача или ошибка
  }
  
  return gear;
}

Пояснения:

Спойлер
  1. Настройка датчиков:
  • Датчики подключаются к цифровым пинам 2 и 3 с поддержкой прерываний.
  • Используются прерывания для точного подсчета импульсов.
  1. Расчет частоты вращения:
  • Частота вычисляется на основе количества импульсов за фиксированный интервал времени (100 мс).
  • Значения преобразуются в RPM (обороты в минуту) для удобства.
  1. Определение передачи:
  • Передаточное число вычисляется как отношение частоты коленвала к частоте вторичного вала.
  • Производится поиск ближайшего передаточного числа из массива gearRatios.
  • Добавлена проверка погрешности (10%) для отсечения ложных срабатываний.
  1. Калибровка:
  • Замените значения в массиве gearRatios на реальные передаточные числа вашего мотоцикла.
  • Настройте pulsesPerEngineRev и pulsesPerWheelRev в соответствии с характеристиками датчиков.

Важные замечания:

  • Для точной работы необходимо использовать датчики с четкими импульсами (например, герконы или霍尔 датчики).
  • Убедитесь, что датчики установлены так, чтобы reliably регистрировать каждый оборот.
  • Для уменьшения шумов можно добавить фильтрацию значений (например, скользящее среднее).

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

1 лайк

Такие датчики нонче редкость! А так выглядит круто, можно продавать!

2 лайка

по братски)
всего тыща)

А дописывать “преобразование” номера передачи в пин @BABOS будет за отдельную мзду?

3 лайка

про выходы не увидел, исправляюсь)

Спойлер
// Константы передаточных чисел
const float K = 2.57142857;  // Передаточное число коленвала к первичному валу
const float K1 = 3.17;       // Передаточное число 1 передачи
const float K2 = 1.81;       // Передаточное число 2 передачи
const float K3 = 1.26;       // Передаточное число 3 передачи
const float K4 = 1.10;       // Передаточное число 4 передачи

// Пинь для выходных сигналов
const int GEAR1_PIN = 9;
const int GEAR2_PIN = 10;
const int GEAR3_PIN = 11;
const int GEAR4_PIN = 12;

// Переменные для хранения оборотов
volatile unsigned long enginePulses = 0;
volatile unsigned long wheelPulses = 0;

// Временные переменные
unsigned long lastUpdateTime = 0;
const unsigned long UPDATE_INTERVAL = 100; // Интервал обновления в мс

// Количество импульсов на оборот для каждого датчика
const int PULSES_PER_ENGINE_REV = 1; // Замените на реальное значение
const int PULSES_PER_WHEEL_REV = 1;  // Замените на реальное значение

void setup() {
  // Настройка пинов выходов
  pinMode(GEAR1_PIN, OUTPUT);
  pinMode(GEAR2_PIN, OUTPUT);
  pinMode(GEAR3_PIN, OUTPUT);
  pinMode(GEAR4_PIN, OUTPUT);
  
  // Инициализация последовательного порта для отладки
  Serial.begin(9600);
  
  // Настройка прерываний для датчиков (замените пины на реальные)
  attachInterrupt(digitalPinToInterrupt(2), countEnginePulse, RISING);
  attachInterrupt(digitalPinToInterrupt(3), countWheelPulse, RISING);
}

void loop() {
  if (millis() - lastUpdateTime >= UPDATE_INTERVAL) {
    // Безопасное чтение значений счетчиков
    noInterrupts();
    unsigned long currentEnginePulses = enginePulses;
    unsigned long currentWheelPulses = wheelPulses;
    enginePulses = 0;
    wheelPulses = 0;
    interrupts();
    
    // Расчет оборотов в минуту
    float RPM1 = (currentEnginePulses * 60000.0) / (UPDATE_INTERVAL * PULSES_PER_ENGINE_REV);
    float RPM2 = (currentWheelPulses * 60000.0) / (UPDATE_INTERVAL * PULSES_PER_WHEEL_REV);
    
    // Определение передачи
    determineGear(RPM1, RPM2);
    
    lastUpdateTime = millis();
  }
}

// Обработчики прерываний для датчиков
void countEnginePulse() {
  enginePulses++;
}

void countWheelPulse() {
  wheelPulses++;
}

// Функция определения передачи
void determineGear(float RPM1, float RPM2) {
  // Сброс всех выходов
  digitalWrite(GEAR1_PIN, LOW);
  digitalWrite(GEAR2_PIN, LOW);
  digitalWrite(GEAR3_PIN, LOW);
  digitalWrite(GEAR4_PIN, LOW);
  
  // Проверка на минимальные обороты для избежания деления на ноль
  if (RPM2 < 10 || RPM1 < 10) {
    return; // Двигатель или вторичный вал не вращаются
  }
  
  // Расчет текущего передаточного отношения
  float currentRatio = (RPM1 / K) / RPM2;
  
  // Определение допуска (5%)
  float tolerance = 0.05;
  
  // Проверка передач
  if (abs(currentRatio - K1) <= K1 * tolerance) {
    digitalWrite(GEAR1_PIN, HIGH);
    Serial.println("1 передача");
  } 
  else if (abs(currentRatio - K2) <= K2 * tolerance) {
    digitalWrite(GEAR2_PIN, HIGH);
    Serial.println("2 передача");
  } 
  else if (abs(currentRatio - K3) <= K3 * tolerance) {
    digitalWrite(GEAR3_PIN, HIGH);
    Serial.println("3 передача");
  } 
  else if (abs(currentRatio - K4) <= K4 * tolerance) {
    digitalWrite(GEAR4_PIN, HIGH);
    Serial.println("4 передача");
  } 
  else {
    Serial.println("Передача не определена");
  }
  
  // Отладочная информация
  Serial.print("RPM1: ");
  Serial.print(RPM1);
  Serial.print(" | RPM2: ");
  Serial.print(RPM2);
  Serial.print(" | Отношение: ");
  Serial.println(currentRatio);
}

но это уже по три)

3 лайка

Т.е. с выжатым сцеплением на ходу откровенно врет? Причем запутывает.

из первого кода

Если мотоцикл движется накатом с выжатым сцеплением, то current_ratio будет неправильным, но мы будем считать, 
что передача не изменилась, пока current_ratio не стабилизируется для новой передачи
(но при выжатом сцеплении передача осталась той же, но current_ratio будет большим, 
так как f_wheel определяется скоростью, а f_engine - холостыми оборотами). 
Поэтому в таком случае мы покажем нейтраль (так как current_ratio не будет соответствовать ни одной передаче).
   Это приемлемо, так как при выжатом сцеплении передача не engaged, и можно считать, что мы на нейтрали.
   Однако, если сцепление отпущено и передача engaged, то current_ratio должен соответствовать передаче.
   Поэтому в целом алгоритм должен работать.

так что тут уже новая задача нарисовывается - “помогите соединить два скетча”)

да и у настоящих пацанов на восходах, никада не было не тормозов и не знали они на какой передаче едут, все по ощущениям)

3 лайка

Я нифига не мотоциклист, по слухам знаю что там секвенталка. Когда разгоняешься - все норм, просто щелкаешь вверх. Проблема когда мотоцикл катится, а какая сейчас передача выставлена - не знаешь. Это на автомобильной коробке по скорости понимаешь, какую передачу произвольную воткнуть. Как мотоциклисты без индикации поступают - не знаю. Возможно, сброс вниз до упора и оттуда считать. Или в голове держать, какая была передача в последний момент. Ибо если воткнуть не ту, да еще на скорости, мягко говоря будет неприятно и небезопасно.

Тахометр! Ну, или по рёву :grinning_face:

С выжатым сцеплением на ходу будет показывать “0”

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

Де? там всего четыре светодиода :slightly_smiling_face:

Вот они че взвывают под окнами… У меня как раз шоссе и светофор.

А что редкого в этих датчиках?
Для вторичного вала используется датчик положения распредвала, а для коленвала импульс от катушки зажигания, он же используется для тахометра и прекрасно работает

это шутка была.

Он у вас стоит?

Там не светодиоды, там семисигментный индикатор