====== Как устроить гонки #Робоняш ======
Нравятся гонки роботов? И нам тоже! Построим своих #Робоняш с 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);
});