КОРЗИНА
магазина
8 (499) 500-14-56 | ПН. - ПТ. 12:00-18:00
ЛЕСНОРЯДСКИЙ ПЕРЕУЛОК, 18С2, БЦ "ДМ-ПРЕСС"

Настройка машинки-музыканта

Если у вас возникли трудности с чётким воспроизведением нот, скорее всего вам необходимо подобрать граничное значение limitValue. Нота начинает звучать, если получаемое с датчика значение меньше limitValue.

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

В данной статье мы производим все расчёты на примере наших значений. Не забывайте, что у вас значения будут отличаться.

Чтение сигналов с датчиков линии

Сперва считаем реальные значения, получаемые с датчиков. Для этого установите машинку на нотную трассу таким образом, чтобы 2 крайних правых датчика (8-й и 9-й) располагались над калибровочными полосками, а все остальные датчики (1-7) находились над белым фоном (чтобы под бампером не было нот). 

Установите бампер в таком положении максимально ровно, чтобы датчики располагались точно над центрами дорожек. 

После  этого загрузите следующий скетч, позволяющий считать значения со всех 9-ти датчиков.

#include <Wire.h>                       // Подключаем библиотеку для работы с аппаратной шиной I2C
#include <iarduino_I2C_Bumper.h>        // Подключаем библиотеку для работы с бампером I2C-flash
iarduino_I2C_Bumper bum(0x0C);          // Объявляем объект bum для работы с функциями и методами библиотеки
void setup(){                          
     Serial.begin(9600);                // Инициируем передачу данных в монитор последовательного порта
     bum.begin();                       // Инициируем работу с бампером
}                                           
void loop(){                                           
  for (uint8_t i = 1; i<= 9; i++){
    Serial.print(bum.getLineAnalog(i)); // Читаем значение с датчика и выводим их в последовательный порт   
    Serial.print(" ");
  }
  Serial.println("");
  delay(100);
}

После загрузки откройте монитор порта.

Вы видите значения, получаемые с датчиков (первый столбик - 1 датчик, второй столбик - 2 и т.д.). Можете снять галочку автопрокрутки, так будет удобнее. 

Видим, что в примерное значение, соответствующее белому фону - 2470 (смотрим первые 7 колонок).

Теперь переставим машинку в место, где есть нота. 

Обратите внимание, существенно изменились значения 6-го датчика, сейчас нота находится как раз под ним. Получаемое с него значение равно примерно 2200.

Итак, мы получили: 

  • 2470 - значение для белого фона;
  • 2200 - значение для ноты.

Исходя из этого можем задать значение limitValue: среднее равно примерно 2300. Это значение можно считать граничным (переходным) между фоном и нотой. Запишите его в скетч и попробуйте запустить машинку. Также можно взять соседние значения (примерно с шагом в 100, т.е. 2400 и 2200). Если чёткого воспроизведения добиться не удалось, двигайтесь дальше. 

Настройка значений калибровочных линий

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

При ровно стоящем бампере значения с калибровочных датчиков равны примерно 1600 (две крайние правые колонки на скриншоте монитора порта).

Сейчас в скетче значения для всех девяти датчиков сравниваются с limitValue. Давайте будем  обрабатывать значения с калибровочных датчиков отдельно. Для этого введём новую переменную limitValueCal. Её значение должно быть немного больше 1600, пусть она будет равна 1700. Можете попробовать задать эту границу больше или меньше, а также взять соседние значения (1600, 1800). 

#include <Wire.h>                                         // Подключаем библиотеку для работы с шиной I2C
#include <iarduino_I2C_Motor.h>                           // Подключаем библиотеку для работы с мотором
#include <iarduino_I2C_Bumper.h>                          // Подключаем библиотеку для работы с бампером I2C-flash
iarduino_I2C_Motor  mot_R (0x0A);                         // Объявляем объект mot_R для правого мотора
iarduino_I2C_Motor  mot_L (0x0B);                         // Объявляем объект mot_L для левого мотора
iarduino_I2C_Bumper  bum (0x0C);                          // Объявляем объект bum для работы с бампером I2C-flash
#define zumPin 6                                          // Зуммер подключен к 6 пину
uint8_t speedMot = 20;                                    // Скорость мотора, % ШИМ
int limitValue = 2400;                                    // Граничное значение, при котором датчик срабатывает на ноту
int limitValueCal = 1600;                                 // Граничное значение датчиков калибровочных линий
const int fre[7] = {262, 294, 330, 349, 392, 440, 466};   // Массив частот нот (до, ре, ми, фа, соль, ля, си бемоль)
uint8_t arr[7] = {0,0,0,0,0,0,0};                         // Массив считанных значений
uint8_t oldArr[7] = {0,0,0,0,0,0,0};                      // Массив предыдущих значений
uint8_t deltaArr[7] = {0,0,0,0,0,0,0};                    // Массив изменившихся с прошлого измерения значений
void setup() {
  mot_R.begin();                                          // Инициируем работу с правым мотором
  mot_L.begin();                                          // Инициируем работу с левым мотором
  mot_R.setDirection(true);                               // Задаём направление вращения правого мотора 
  mot_L.setDirection(false);                              // Задаём направление вращения левого мотора  
  bum.begin();                                            // Инициируем работу с бампером (датчиком линии)
}
void loop() { 
  if (bum.getLineAnalog(8) < limitValueCal && bum.getLineAnalog(9) < limitValueCal){ // Если линия под двумя датчиками, едем прямо
    mot_L.setSpeed(speedMot, MOT_PWM);                    // Включаем левый мотор
    mot_R.setSpeed(speedMot, MOT_PWM);                    // Включаем правый мотор
  }  
  else if (bum.getLineAnalog(8) < limitValueCal){         // Иначе, если линия только под левым датчиком
    mot_L.setSpeed(speedMot-speedMot/3, MOT_PWM);         // Уменьшаем скорость левого мотора
    mot_R.setSpeed(speedMot, MOT_PWM);                    // Включаем правый мотор
  }
  else if (bum.getLineAnalog(9) < limitValueCal){         // Иначе, если линия только под правым датчиком
    mot_L.setSpeed(speedMot, MOT_PWM);                    // Включаем левый мотор
    mot_R.setSpeed(speedMot-speedMot/3, MOT_PWM);         // Уменьшаем скорость правого мотора
  } 
  for (uint8_t i = 0; i <= 6; i++){                       // Чтение датчиков
    arr[i] = bum.getLineAnalog(i+1) < limitValue ? 1 : 0; // Если значение с датчика меньше граничного, записываем в массив 1, иначе 0 
  }                                                                                                  
  for (uint8_t i = 0; i <= 6; i++){                       // Вычисление разницы текущего и предыдущего массива
    deltaArr[i] = abs(arr[i] - oldArr[i]);                // Записываем в массив отличия (по модулю)
  }
  for (uint8_t i = 0; i <= 6; i++){                       // Обновляем предыдущий массив
      oldArr[i] = arr[i];
  }
  uint8_t sum = 0;                                        // Создаём переменную
   for (uint8_t i = 0; i <= 6; i++){                      // Вычисляем  сумму значений массива
    sum += arr[i];
  }
 if (sum == 0) noTone(zumPin);                            // Если все элементы массива равным 0, выключаем зуммер
  else {
    for (uint8_t i = 0; i <= 6; i++){                     // Иначе ищем первое изменившееся значение в массиве
      if (deltaArr[i] != 0) {                              
        tone(zumPin, fre[i]);                             // Воспроизводим зуммером соответствующую ноту
        break;                                            
      }}}}

Обычно этого достаточно для стабильной работы машинки. Если стабильной работы добиться не удалось, переходите к следующему пункту.

Распознавание нот по массиву значений

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

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

Для получения этих значений посмотрим на значения бампера, полученные при отсутствии нот под ним (первый пункт данного урока, первый скриншот).

Отнимем примерно 100-200 от значения каждого значения (1-7 датчик) и запишем в массив граничных значений limitValueArr (10 строка). Мы отняли 150. В нашем случае при таком значении наблюдалось самое устойчивое воспроизведение. 

#include <Wire.h>                                         // Подключаем библиотеку для работы с шиной I2C
#include <iarduino_I2C_Motor.h>                           // Подключаем библиотеку для работы с мотором
#include <iarduino_I2C_Bumper.h>                          // Подключаем библиотеку для работы с бампером I2C-flash
iarduino_I2C_Motor  mot_R (0x0A);                         // Объявляем объект mot_R для правого мотора
iarduino_I2C_Motor  mot_L (0x0B);                         // Объявляем объект mot_L для левого мотора
iarduino_I2C_Bumper  bum (0x0C);                          // Объявляем объект bum для работы с бампером I2C-flash
#define zumPin 6                                          // Зуммер подключен к 6 пину
uint8_t speedMot = 20;                                    // Скорость мотора, % ШИМ
int limitValueCal = 1600;                                 // Граничное значение датчиков калибровочных линий
int limitValueArr[7] = {2531, 2325, 2421, 2335, 2317, 2320, 2309}; // Граничное значение каждого датчка
const int fre[7] = {262, 294, 330, 349, 392, 440, 466};   // Массив частот нот (до, ре, ми, фа, соль, ля, си бемоль)
uint8_t arr[7] = {0,0,0,0,0,0,0};                         // Массив считанных значений
uint8_t oldArr[7] = {0,0,0,0,0,0,0};                      // Массив предыдущих значений
uint8_t deltaArr[7] = {0,0,0,0,0,0,0};                    // Массив изменившихся с прошлого измерения значений
void setup() {
  mot_R.begin();                                          // Инициируем работу с правым мотором
  mot_L.begin();                                          // Инициируем работу с левым мотором
  mot_R.setDirection(true);                               // Задаём направление вращения правого мотора 
  mot_L.setDirection(false);                              // Задаём направление вращения левого мотора  
  bum.begin();                                            // Инициируем работу с бампером (датчиком линии)
}
void loop() { 
  if (bum.getLineAnalog(8) < limitValueCal && bum.getLineAnalog(9) < limitValueCal){ // Если линия под двумя датчиками, едем прямо
    mot_L.setSpeed(speedMot, MOT_PWM);                    // Включаем левый мотор
    mot_R.setSpeed(speedMot, MOT_PWM);                    // Включаем правый мотор
  }  
  else if (bum.getLineAnalog(8) < limitValueCal){         // Иначе, если линия только под левым датчиком
    mot_L.setSpeed(speedMot-speedMot/3, MOT_PWM);         // Уменьшаем скорость левого мотора
    mot_R.setSpeed(speedMot, MOT_PWM);                    // Включаем правый мотор
  }
  else if (bum.getLineAnalog(9) < limitValueCal){         // Иначе, если линия только под правым датчиком
    mot_L.setSpeed(speedMot, MOT_PWM);                    // Включаем левый мотор
    mot_R.setSpeed(speedMot-speedMot/3, MOT_PWM);         // Уменьшаем скорость правого мотора
  } 
  for (uint8_t i = 0; i <= 6; i++){                       // Чтение датчиков
    arr[i] = bum.getLineAnalog(i+1) < limitValueArr[i] ? 1 : 0; // Если значение с датчика меньше граничного, записываем в массив 1, иначе 0 
  }                                                                                                  
  for (uint8_t i = 0; i <= 6; i++){                       // Вычисление разницы текущего и предыдущего массива
    deltaArr[i] = abs(arr[i] - oldArr[i]);                // Записываем в массив отличия (по модулю)
  }
  for (uint8_t i = 0; i <= 6; i++){                       // Обновляем предыдущий массив
      oldArr[i] = arr[i];
  }
  uint8_t sum = 0;                                        // Создаём переменную
   for (uint8_t i = 0; i <= 6; i++){                      // Вычисляем  сумму значений массива
    sum += arr[i];
  }
 if (sum == 0) noTone(zumPin);                            // Если все элементы массива равным 0, выключаем зуммер
  else {
    for (uint8_t i = 0; i <= 6; i++){                     // Иначе ищем первое изменившееся значение в массиве
      if (deltaArr[i] != 0) {                              
        tone(zumPin, fre[i]);                             // Воспроизводим зуммером соответствующую ноту
        break;                                            
      }}}}



Обсуждение

Гарантии и возврат Используя сайт Вы соглашаетесь с условями