Как устроить гонки #Робоняш

Нравятся гонки роботов? И нам тоже! Построим своих #Робоняш с NFC-сканером и bluetooth-модулем, а затем устроим сражение за звание последнего героя. Интересно? Тогда приступим…

Нам потребуется

Видеообзор

Сборка

Собирём Робоняшу по инструкции из набора, а затем добавим новые модули. Сначала добавим ещё один аккумулятор — Power Shield. Матрица, NFC-модуль и Bluetooth потребляют много энергии, поэтому один Power Bank долго не протянет.

На Power Shield закрепим Motor Shield.

Не забудьте добавить перемычку на MotorShield и снять джампер PWR JOIN. Если этого не сделать, плата может выйти из строя.

Установите Troyka Shield LP.

Подключите периферийные модули #Робоняши.

Аккуратно уберите провода и закрепите Troyka Slot Shield.

Подключите модули NFC и Bluetooth. Антенну NFC-сканера прикрепите плашкой #Структора 2×2 к креплениям датчиков линии.

Соревнование

Каждая #Робоняша должна иметь своё имя, поэтому не забудьте изменить их в скетче. После этого загрузите программу в робота.

Для управления скачайте на смартфон приложение Arduino Bluetooth RC Car.

Цель игры — первым объехать максимальное количество наклеенных на трассу NFC-меток. Метки добавляют призовые очки только первому нашедшему её роботу. Игра заканчивается, когда все метки найдены. Кто набрал больше очков — тот и победил.

Код игры

RoboNY.js
/*----- Подключение модулей -----*/ {
  Serial3.setup(9600);
  var bt = require('@amperka/bluetooth').connect({serial: Serial3,  kPin: P5, speed: 9600});
  var Motor = require('@amperka/motor');
  var symbols = require('@amperka/basic-font').font;
  PrimaryI2C.setup({sda: SDA, scl: SCL, bitrate: 400000});
  var matrix = require('@amperka/led-matrix').connect(PrimaryI2C);
  var nfc = require('@amperka/nfc').connect({i2c: I2C1, irqPin: P2});
  var player = require('@amperka/ringtone').create(P3);
  var motorOne = Motor.connect({phasePin: P4, pwmPin: A3, freq: 100});
  var motorTwo = Motor.connect({phasePin: P7, pwmPin: P6, freq: 100});
  var resetButton = require('@amperka/button').connect(C4);
}
 
/*----- Данными по умолчанию -----*/ {
  // переменая для хранения значение скорости
  var velocity = 0;
  // это число мы будем использовать в логике поворотов
  var defaultSpeed = 0.5;
  // Счётчик считанных меток
  var counter = 0;
  // Номер страницы для чтения и записи
  var page2read = 5;
  // Символы, используемые для вывода на светодиодную матрицу
  var amperka = '0123456789';
  // длина строки с символами
  var len = 10;
  // массив который ищем
  var bufferRead = [0, 0, 0, 0];
  // массив который запишем
  var bufferWrite = [1, 1, 1, 1];
  //мелодия воспроизводимая при считывании новой метки
  var melody = 'HeyBaby:d=4,o=5,b=700:8a4,16a#4,16b4,16c,16c#,16d,16d#' 
                     +',16e,16f,16f#,16g,16g#,16a,16a#,16b,16c6,8c#6,16d6,16d#6,16e6,16f6,p,p';
  // Значение яркости матрицы
  var BRIGHTNESS_VALUE = 0.1;
}
 
//------------------------------------------------------------------------------------------
// НАЗВАНИЕ МОДУЛЯ  BLUETOOTH
var bt_name = 'RoboNY1';
//------------------------------------------------------------------------------------------
 
nfc.wakeUp(function(error) {
  if (error) {
    print('wake up error', error);
  } else {
    print('wake up OK');
    // слушаем новые метки
    matrixWriter();
    nfc.listen();
    bt. disconnect(function (error) {
      console.log('disconnected');
    });
    bt.name(bt_name, function (error) {
      console.log('name change');
    });
  }
});
 
 
//------------------------------------------------------------------------------------------
// ЕСЛИ ДВИГАТЕЛИ ВРАЩАЮТСЯ В РАЗНЫЕ СТОРОНЫ ПРИ ДВИЖЕНИИ ВПЕРЁД, ПОМЕНЯТЬ ЗНАКИ У АРГУМЕНТОВ
var drive = function(motorOne1, motorTwo2) {
  motorOne.write(motorOne1);
  motorTwo.write(-motorTwo2);
};
//------------------------------------------------------------------------------------------
 
bt.on('error', function (error) {
  console.log(error);
});
 
bt.on('data', function (dataIn) {
  console.log(dataIn);
  if (dataIn === 'F') {
    // если пришла команда "F"
    // едем вперёд
    drive(velocity, velocity);
  } else if (dataIn === 'B') {
    // или если пришла команда "B"
    // едем назад
    drive(-velocity, -velocity);
  } else if (dataIn === 'L') {
    // или если пришла команда "L"
    // поворачиваем налево на месте
    drive(-velocity, velocity);
  } else if (dataIn === 'R') {
    // или если пришла команда "R"
    // поворачиваем направо на месте
    drive(velocity, -velocity);
  } else if (dataIn === 'I') {
    // или если пришла команда "I"
    // едем вперёд и направо
    drive(defaultSpeed + velocity, defaultSpeed - velocity);
  } else if (dataIn === 'J') {
    // или если пришла команда "J"
    // едем назад и направо
    drive(-defaultSpeed - velocity, -defaultSpeed + velocity);
  } else if (dataIn === 'G') {
    // или если пришла команда "G"
    // едем вперёд и налево
    drive(defaultSpeed - velocity, defaultSpeed + velocity);
  } else if (dataIn === 'H') {
    // или если пришла команда "H"
    // едем назад и налево
    drive(-defaultSpeed + velocity, -defaultSpeed - velocity);
  } else if (dataIn === 'S') {
    // или если пришла команда "S"
    // стоим
    drive(0, 0);
  } else if (((dataIn - '0') >= 0) && ((dataIn - '0') <= 9)) {
    // или если пришло значение от 0 до 9
    // сохраняем новое значение скорости
    velocity = (dataIn - '0') * 0.1;
  } else if (dataIn === 'q') {
    // или если пришла "q"
    // полный газ
    velocity = 1;
  }
});
 
 
 
nfc.on('tag', function(error, data) {
  if (error) {
    print('tag read error');
  } else {
    // выводим в консоль полученные данные
    print(data);
    // читаем указанную страницу данных
    nfc.readPage(page2read, function(error, buffer) {
      if (error) {
        print('page read error');
      } else {
        print('page read result: ', buffer);
        // проверяем метку,
        for (var i in buffer) {
          if (buffer[i] === bufferRead[i]) {
            if (i === buffer.length-1) {
              matrixWriter();
              writeCard();
              voiceOn();
            }
          }
        }
      }
    });
  }
  // каждые 150 миллисекунд слушаем новую метку
  setTimeout(function () {
    nfc.listen();
  }, 150);
});
 
// при нажатии на кнопку сбрасываем текущий счёт
resetButton.on('click', function() {
  counter = 0;
  matrixWriter();
});
 
 
// вывод на матрицу символа
function matrixWriter() {
  var char = amperka[counter];
  counter += 1;
  if (counter === len) {
    counter = 0;
  } else {
  }
  matrix.brightness(BRIGHTNESS_VALUE);
  matrix.print(symbols[char]);
}
 
// запись на карту страницы
function writeCard() {
  nfc.writePage(page2read, bufferWrite, function(error) {
    if (error) {
      print('write page ERROR');
    } else {
      print('write page OK');
    }
  });
}
 
// проигрывание мелодии
function voiceOn() {
  player.stop();
  player.play(melody);
}

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

Код активации меток

reActiveTAG.js
// настраиваем I2C1 для работы модуля
I2C1.setup({sda: SDA, scl: SCL, bitrate: 400000});
 
// подключаем модуль к I2C1 и пину прерывания
var nfc = require('@amperka/nfc').connect({i2c: I2C1, irqPin: P2});
var bufferWrite = [0, 0, 0, 0];
 
 
// активируем модуль
nfc.wakeUp(function(error) {
  if (error) {
    print('wake up error', error);
  } else {
    print('wake up OK');
    // слушаем новые метки
    nfc.listen();
  }
});
 
// указываем страницу для чтения данных
var page2read = 5;
 
nfc.on('tag', function(error, data) {
  if (error) {
    print('tag read error');
  } else {
    // выводим в консоль полученные данные
    print(data);
    // читаем указанную страницу данных
    nfc.readPage(page2read, function(error, buffer) {
      if(error) {
        print('page read error');
      } else {
        print('page read result: ', buffer);
        // обновляем данные для записи. Например, увеличиваем на единицу
        for (var i in buffer) {
          buffer[i] = bufferWrite[i];
        }
        // перезаписываем метку новыми данными на ту же страницу
        nfc.writePage(page2read, buffer, function(error) {
          if (error) {
            print('write page ERROR');
          } else {
            print('write page OK');
          }
        });
      }
    });
  }
  // каждые 1000 миллисекунд слушаем новую метку
  setTimeout(function () {
    nfc.listen();
  }, 1000);
});