Тахометр с датчиками Холла

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

независимо от диаметра колеса?

ориентировался на - Robot_4WD - там колесо в диаметре сантиметров 6

Да на это чихать, тут главное под каждым деревом ногу задрать))

4 лайка

пить надо меньше, а то мозги с мочёй вытекают…

До того как я перейду ко второй части сообщения я хочу уточнить если я правильно понимаю:
Это пример из ссылки выше:

int pin = 13;
volatile int state = LOW;
 
void setup(){
  pinMode(pin, OUTPUT);
  attachInterrupt(0, blink, CHANGE);
}
 
void loop(){
  digitalWrite(pin, state);
}
 
void blink(){
  state = !state;
}

Когда двигатель крутится, т.е. датчик Холла подключен к порту D2 и меняет значения на порту 0 (D2) с LOW на HIGH и наоборот, выполняется прерывание (останавливается выполнение основного кода из void loop() и выполняется код void blink(), далее продолжается выполнение из void loop() до следующего изменения значения на порту D2.
Если это так, то мне нужно менять пины датчиков Холла?

почитайте здесь по прерываниям, пример актуален для UNO-NANO для MEGA2560 поищите

Если нужно независимо считать скорости по четырем моторам, то нужны четыре независимые метрики “скорость”, которые корректируются в независимых обработчиках прерываний (функциях), привязанных к разным входам МК. У Мега2560 достаточно “простых” прерываний, чтобы это реализовать.

Я перепроверил, у меня как раз вторая пара датчиков Холла висят на пинах 2, 3, 18, 19. Это то что нужно. Спасибо. Буду продолжать учиться и работать над тем чтобы в итоге все получилось)

Обратите внимание на макрос digitalPinToInterrupt(), описанный в примере здесь: https://cdn.arduino.cc/reference/en/language/functions/external-interrupts/attachinterrupt/

Он облегчит жизнь.

1 лайк

Выполнено :white_check_mark: и даже компилируется (уже с digitalPinToInterrupt())

У меня моторы с редуктором точно не скажу но примерно 150-300(мотор) / 1(колесо) оборотов. (если вообще это важно).
Если кто знает “литературу” мне в помощь, как считать срабатывания датчика (чем проще, тем лучше).

Ну, это же с первого раза находится: Ардуино: тахометр на прерываниях | Класс робототехники - Part 3

Не увидел в статье атомарного чтения переменной spd, правда. Могут быть проблемы.

Берем мотор с редуктором, скажем, отсюда:

Редуктор выбираем на 5 rpm при 3 В.
Это соответствует 0,08333333 об/сек = 0,5236 рад/сек. Т.е. если 0,5236 радиуса колеса меньше 25.4 мм, то колесо считается не крутящимся.
Т.е. если диаметр колеса меньше 97 мм, колесо считается не крутящимся.

Пример для двух двигателей и вопрос

#define PIN_LED 47

unsigned int rotA = 0;
unsigned int rotB = 0;
unsigned long int tm;
volatile unsigned long int spdA = 0;
volatile unsigned long int spdB = 0;
unsigned int dt = 0;

void HalA() {
    rotA++; // прибавляем единичку к счётчику обротов
    dt = millis() - tm; // вычисляем время с последнего расчёта
    if( dt >= 100 ){ // если прошло 100мс или более, то начинаем расчёт
        spdA = rotA*60000/dt;
        rotA = 0; // обнуляем счётчик
        tm = millis(); // запоминаем время расчёта
    }
}

void HalB() {
    rotB++; // прибавляем единичку к счётчику обротов
    dt = millis() - tm; // вычисляем время с последнего расчёта
    if( dt >= 100 ){ // если прошло 100мс или более, то начинаем расчёт
        spdB = rotB*60000/dt;
        rotB = 0; // обнуляем счётчик
        tm = millis(); // запоминаем время расчёта
    }
}

void setup() {
    pinMode(PIN_LED, OUTPUT);

    attachInterrupt(digitalPinToInterrupt(5), HalA, CHANGE); //новое
    attachInterrupt(digitalPinToInterrupt(4), HalB, CHANGE); //новое

    tm = millis();
}

void loop() {
    if(spdA <= 100 || spdB <= 100){
    digitalWrite(PIN_LED, HIGH);      
    }
      else{
      digitalWrite(PIN_LED, LOW);
      }
}

Переменные для вычисления времени с последнего расчёта ( tm и dt) можно использовать общими для расчета в один период времени или их можно разделить, например ( tmA dtA и tmB dtB ) ?

ты чёто как то заумно считаешь, один оборот колеса в секунду, при диаметре 64 мм это порядка 200мм, диск датчика выдаёт порядка 10 импульсов за оборот, то-есть если за секунду не поступило ни одного импульса то колесо считаем стоящим, хотя это всё навскидку, по памяти, по диаметру колесо может немного больше, а вот число импульсов брал минимум, там точно прорезей больше…
Датчики холла на эти детские шелогрушки не ставят…

volatile unsigned long int spdA = 0;
volatile unsigned long int spdB = 0;

только для переменной spd нужно прописать volatile или для всех переменных в функции?

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

1 лайк

Не можно, а нужно. Прерывания возникают в разные моменты времени и эти моменты должны быть зафиксированы раздельно, а не замещаться друг другом.

dt, к слову - переменная локальная для прерывания, глобальной ей быть не обязательно.

Атомарность при чтении: Энкодер от прерывания INT1 | Аппаратная платформа Arduino

Чукча не читатель, чукча - писатель?
Еще раз: 5 rpm - это один оборот в 12 секунд. Т.е. 10 датчиков недостаточно, чтобы гарантировать, что хоть один сработает.
И диаметр в этом случае нам пофигу. Диаметр нужен, если мы поворот колеса считаем в дюймах, а не в оборотах (как в процитированном мною сообщении).

Понял. Исправлю. Спасибо.
Я только в воскресенье смогу проверить скетч в работе. Как проверю, сразу отпишусь, получилось или нет.

Всем большое спасибо за помощь. Узнал много нового!