====== Как устроить гонки #Робоняш ====== Нравятся гонки роботов? И нам тоже! Построим своих #Робоняш с NFC-сканером и bluetooth-модулем, а затем устроим сражение за звание последнего героя. Интересно? Тогда приступим... {{ :робототехника:robot-battle:robo-battle.jpg?nolink |}} ==== Нам потребуется ==== * Базовый набор [[amp>product/robonyasha-iskra-js?utm_source=man&utm_campaign=NTAG216&utm_medium=wiki|«Робоняша»]] Дополнительные модули: * [[amp>product/arduino-power-shield-li-ion?utm_source=man&utm_campaign=NTAG216&utm_medium=wiki|PowerShield]] * [[amp>product/arduino-troyka-shield-lp?utm_source=man&utm_campaign=NTAG216&utm_medium=wiki|Troyka Shield LP]] * [[amp>product/arduino-troyka-slot-shield?utm_source=man&utm_campaign=NTAG216&utm_medium=wiki|Troyka Slot Shield]] * [[amp>product/troyka-rfid-nfc-1356?utm_source=man&utm_campaign=NTAG216&utm_medium=wiki|NFC-сканер]] * [[amp>product/troyka-bluetooth-hc-05?utm_source=man&utm_campaign=NTAG216&utm_medium=wiki|Bluetooth-модуль]] * [[amp>product/troyka-led-matrix?utm_source=man&utm_campaign=NTAG216&utm_medium=wiki|Монохромная LED матрица 8×8]] * [[amp>product/troyka-buzzer?utm_source=man&utm_campaign=NTAG216&utm_medium=wiki|Зуммер]] * [[amp>product/structor-troyka|Крепления Troyka (#Структор)]] * [[amp>product/rfid-ntag-216?utm_source=man&utm_campaign=NTAG216&utm_medium=wiki|NFC]] метки — чем больше, тем лучше ===== Видеообзор ===== {{youtube>ntLcI-y5xbs?large}} ==== Сборка ==== {{http://wiki.amperka.ru/_media/robot:robonyasha-amperka-18-web.pdf|Собирём Робоняшу}} по инструкции из набора, а затем добавим новые модули. Сначала добавим ещё один аккумулятор — ''Power Shield''. Матрица, NFC-модуль и Bluetooth потребляют много энергии, поэтому один Power Bank долго не протянет. {{ :робототехника:robot-battle:robot-battle_iskra-js_power-bank.png?nolink |}} На ''Power Shield'' закрепим ''Motor Shield''. {{ :робототехника:robot-battle:robot-battle_power-bank_motor-shield.png?nolink |}} Не забудьте добавить перемычку на MotorShield и снять джампер ''PWR JOIN''. Если этого не сделать, плата может выйти из строя. {{ :робототехника:robot-battle:robot-battle_motor-shield_motor-12mm_power-bank-li-on.png?nolink |}} Установите ''Troyka Shield LP''. {{ :робототехника:robot-battle:motor-shield_motor-12mm_troyka-shield-lp.png?nolink |}} Подключите периферийные модули #Робоняши. {{ :робототехника:robot-battle:robot-battle_troyka-shield-lp_all_sens.png?nolink |}} Аккуратно уберите провода и закрепите ''Troyka Slot Shield''. {{ :робототехника:robot-battle:robot-battle_troyka-shield-lp_all_sens_slot.png?nolink |}} Подключите модули NFC и Bluetooth. Антенну NFC-сканера прикрепите плашкой #Структора 2×2 к креплениям датчиков линии. {{ :робототехника:robot-battle:robot-battle_troyka-slot-shield_nfc_bluetooth_1.png?nolink |}} ===== Соревнование ===== Каждая #Робоняша должна иметь своё имя, поэтому не забудьте изменить их в скетче. После этого загрузите программу в робота. Для управления скачайте на смартфон приложение [[https://play.google.com/store/apps/details?id=braulio.calle.bluetoothRCcontroller&hl=ru|Arduino Bluetooth RC Car]]. Цель игры — первым объехать максимальное количество наклеенных на трассу NFC-меток. Метки добавляют призовые очки только первому нашедшему её роботу. Игра заканчивается, когда все метки найдены. Кто набрал больше очков — тот и победил. ==== Код игры ==== /*----- Подключение модулей -----*/ { 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); } Чтобы вернуть метки в активное состояние и повторить заезд — воспользуйтесь кодом обнуления. Вы можете прошить его в одну из #Няш, но лучше собрать отдельное устройство. ==== Код активации меток ==== // настраиваем 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); });