Простая и эффективная нейросеть, которую мы использовали в проекте НейроБашня, нам так понравилась, что мы решили сделать еще один проект с похожей основой.
В проекте НейроТир мы создадим мишень, которая будет самообучаться противостоять игроку, стреляющему по ней, подстраиваясь под его манеру и опыт стрельбы и предлагая все более сложные для него комбинации целей.
"Пистолет", из которого будет вестись стрельба по мишени, спроектирован на основе LEGO Mindstorrms NXT. Для стрельбы мы будем использовать лазерную указку, включенную на постоянное свечение. Луч лазера будет перекрываться специальной заслонкой, управляемой малым EV3-мотором и ПИД-регулятором.В роли спускового курка выступает датчик кнопка.
Для обучения нейронной сети в мишени необходима обратная связь от пистолета, чтобы она могла сопоставить момент выстрела и факт поражения цели. Такую связь мы реализуем посредством bluetooth. В момент выстрела пистолет посылает мишени "1".
Программа для пистолета выглядит следующим образом:
#define BT_CONN 1
#define OUTBOX 5
long time=0;
int tri =1;
int triger=1;
int yes=0;
int es=0;
int u=0;
int Pk=3.5;
int PD=7;
int e=0;
void Send2BT()
{
SendRemoteNumber(BT_CONN,OUTBOX,1);
}
void BTConnect()
{
CommBTConnectionType args;
args.Name = "ks2";
args.ConnectionSlot = BT_CONN;
args.Action = true;
if(BluetoothStatus(BT_CONN)!=NO_ERR) SysCommBTConnection(args);
}
task pid()
{
es=0;
while(true){
e = MotorRotationCount(OUT_A)-yes;
u = e*Pk+PD*(e-es);
if(u>100){
u=100;
}
if(u<-100){
u=-100;
}
OnRev(OUT_A,u);
es = e;
}
}
task main()
{
ResetRotationCount(OUT_A);
start pid;
time=CurrentTick();
SetSensorTouch(IN_1);
BTConnect();
while(true){
if(Sensor(IN_1)==1){
yes=60 * triger;
triger=triger*-1;
for(int i=1500;i>300;i=i-50)
{
PlayTone(i,10);
Wait(10);
}
Send2BT();
}
if(CurrentTick()-time>=500){
time=CurrentTick();
yes=0;
Wait(700);
}
}
}
В основе мишени лежит еще один блок NXT, который управляет тремя NXT-моторами. Каждый мотор управляет заслонкой соответствующей цели, в качестве которой используется датчик освещенности. Для того, чтобы увеличить "зону поражения" лазером, сберечь фотодиод датчика при прямых попаданиях, используется рассеивающие фильтры из бумаги, а для устранения фоновой засветки - бленды из покрышек, как в проекте "LEGO UART: бит за битом". Если цель поражена - соответствующая заслонка закрывается, если игрок промахнулся - не пораженная цель вспыхивает красным цветом (используестя подсветка датчиков освещенности).
Нейронная сеть обучается на основе истории попаданий игрока в мишень, учитывается 3 последних выстрела.
Если представить алгоритм обучения нейронной сети в упрощенной форме в терминологии "коробков и камушков", получится следующее:
После нескольких циклов обучения вероятности того, что нейронная сеть станет выбирать сложные для поражения конкретным игроком цели будет становится выше, причем процесс обучения будет продолжаться в процессе игры, постоянно подстраиваясь к мастерству игрока, выискивая его слабые места и предлагая все более сложные комбинации целей.
Для обучения нейронной сети в мишени необходима обратная связь от пистолета, чтобы она могла сопоставить момент выстрела и факт поражения цели. Такую связь мы реализуем посредством bluetooth. В момент выстрела пистолет посылает мишени "1".
Программа для пистолета выглядит следующим образом:
#define BT_CONN 1
#define OUTBOX 5
long time=0;
int tri =1;
int triger=1;
int yes=0;
int es=0;
int u=0;
int Pk=3.5;
int PD=7;
int e=0;
void Send2BT()
{
SendRemoteNumber(BT_CONN,OUTBOX,1);
}
void BTConnect()
{
CommBTConnectionType args;
args.Name = "ks2";
args.ConnectionSlot = BT_CONN;
args.Action = true;
if(BluetoothStatus(BT_CONN)!=NO_ERR) SysCommBTConnection(args);
}
task pid()
{
es=0;
while(true){
e = MotorRotationCount(OUT_A)-yes;
u = e*Pk+PD*(e-es);
if(u>100){
u=100;
}
if(u<-100){
u=-100;
}
OnRev(OUT_A,u);
es = e;
}
}
task main()
{
ResetRotationCount(OUT_A);
start pid;
time=CurrentTick();
SetSensorTouch(IN_1);
BTConnect();
while(true){
if(Sensor(IN_1)==1){
yes=60 * triger;
triger=triger*-1;
for(int i=1500;i>300;i=i-50)
{
PlayTone(i,10);
Wait(10);
}
Send2BT();
}
if(CurrentTick()-time>=500){
time=CurrentTick();
yes=0;
Wait(700);
}
}
}
В основе мишени лежит еще один блок NXT, который управляет тремя NXT-моторами. Каждый мотор управляет заслонкой соответствующей цели, в качестве которой используется датчик освещенности. Для того, чтобы увеличить "зону поражения" лазером, сберечь фотодиод датчика при прямых попаданиях, используется рассеивающие фильтры из бумаги, а для устранения фоновой засветки - бленды из покрышек, как в проекте "LEGO UART: бит за битом". Если цель поражена - соответствующая заслонка закрывается, если игрок промахнулся - не пораженная цель вспыхивает красным цветом (используестя подсветка датчиков освещенности).
Нейронная сеть обучается на основе истории попаданий игрока в мишень, учитывается 3 последних выстрела.
Если представить алгоритм обучения нейронной сети в упрощенной форме в терминологии "коробков и камушков", получится следующее:
- Возьмем 64 пустые коробки и расположим их в виде куба 4x4x4, в каждую такую коробку положим по 1 камешку трех разных цветов (каждый цвет соответствует одной из целей) - это "мозг" нашего самообучающегося робота
- Возьмем лист бумаги и будем записывать на него историю выстрелов, в какую мишень в каком порядке стрелял игрок. Из этой истории нас будут интересовать три последние выстрела.
- Предположим игрок уже сделал 3 выстрела и их история зафиксирована на бумаге, например 3,1,2. Первые три цели выбираются случайным образом, нейронная сеть в их выборе не участвует.
- В "кубе" с коробками выбираем 3 коробку в 1 ряду во втором слое и наугад вытягиваем один из камней, смотрим его цвет и кладем обратно. В зависимости от цвета камня поднимаем соответствующую мишень, предлагая игроку попасть в нее.
- Если игрок промахнулся мимо выставленной цели, добавляем в коробку камень того цвета, который достали.
- Если игрок попал в выставленную цель, убираем из коробки вытащенный камень проверив предварительно что в ней есть еще камне такого цвета. Последний камень каждого цвета всегда оставляем в коробке, таким образом число камней в коробке не может быть меньше 3 (по 1 каждого цвета).
- Фиксируем в истории выстрелов цель, в которую стрелял игрок, например 3, Получаем историю - 3,1,2,3. "Забываем" самый первый выстрел, помним всегда только последние 3 - итого в истории 1,2,3.
- Переходим на шаг 4, оперируя новой историей выстрелов
#define BT_CONN 0
#define INBOX 5
float l1,l2,l3;
int BTMailbox = 0;
long BTtime = 0;
float random;
long time1, time2, time3;
int x=0, y=0, z=0;
int triger = 1, triger2 = 0;
int target=0;
int history[3]={0,0,0};
int brain[4][4][4][4];
int position1=0, position2=0, position3=0;
int es1=0, es2=0, es3=0;
int u1=0, u2=0, u3=0;
int e1,e2,e3;
float Pk=3;
float PD=6;
bool BTCheck(int conn)
{
if (BluetoothStatus(conn) == NO_ERR) return true;
else return false;
}
task pid()
{
while(true){
e1 = MotorRotationCount(OUT_A)-position1;
e2 = MotorRotationCount(OUT_B)-position2;
e3 = MotorRotationCount(OUT_C)-position3;
u1 = e1*Pk+PD*(e1-es1);
u2 = e2*Pk+PD*(e2-es2);
u3 = e3*Pk+PD*(e3-es3);
if(u1>100) u1=100;
if(u2>100) u2=100;
if(u3>100) u3=100;
if(u1<-100) u1=-100;
if(u2<-100) u2=-100;
if(u3<-100) u3=-100;
if(abs(e1)>15) OnRev(OUT_A,u1);
else Off(OUT_A);
es1 = e1;
if(abs(e2)>15) OnRev(OUT_B,u2);
else Off(OUT_B);
es2 = e2;
if(abs(e3)>15) OnRev(OUT_C,u3);
else Off(OUT_C);
es3 = e3;
}
}
task main(){
OnFwd(OUT_ABC,18);
Wait(3000);
for(int x=0;x<=3;x++){
for(int y=0;y<=3;y++){
for(int z=0;z<=3;z++){
for(int t=0;t<=3;t++){
brain[x][y][z][t]=1;
}
}
}
}
ResetRotationCount(OUT_A);
ResetRotationCount(OUT_B);
ResetRotationCount(OUT_C);
Wait(3000);
Off(OUT_ABC);
start pid;
SetSensorColorNone(IN_3);
SetSensorLight(IN_2,0);
SetSensorLight(IN_1,0);
position1=-80;
position2=-80;
position3=-80;
Wait(500);
l1=Sensor(IN_1);
l2=Sensor(IN_2);
l3=Sensor(IN_3);
position1=-30;
position2=-30;
position3=-30;
while(true){
if(triger>0){
x=brain[history[0]][history[1]][history[2]][1];
y=brain[history[0]][history[1]][history[2]][2];
z=brain[history[0]][history[1]][history[2]][3];
random = abs(Random((x+y+z)*1000)/1000.0);
if(random<=x ){
position1=-80;
target=1;
}
else {
if(random<=x+y){
position2=-80;
target=2;
}
else{
if(random<=x+y+z){
position3=-80;
target=3;
}
}
}
}
BTMailbox=0;
while(BTMailbox==0){
if (BTCheck(BT_CONN)) {
ReceiveRemoteNumber(INBOX, true, BTMailbox);
}
}
triger=0;
if(target == 1){
if(Sensor(IN_1)>=l1+0.01){
position1= -30;
Wait(1000);
triger+=1;
}
else{
triger2=1;
SetSensorLight(IN_1,1);
Wait(500);
SetSensorLight(IN_1,0);
}
}
if(target== 2){
if(Sensor(IN_2)>=l2+0.01){
position2= -30;
Wait(1000);
triger+=1;
}
else{
SetSensorLight(IN_2,1);
Wait(500);
SetSensorLight(IN_2,0);
triger2=2;
}
}
if(target==3){
if(Sensor(IN_3)>=l3+0.01){
position3= -30;
Wait(1000);
triger+=1;
}
else{
SetSensorColorRed(IN_3);
Wait(500);
SetSensorColorNone(IN_3);
triger2=3;
}
}
if(triger==0) brain[history[0]][history[1]][history[2]][target]+=1;
else{
if(brain[history[0]][history[1]][history[2]][target]>1){
brain[history[0]][history[1]][history[2]][target]-=1;
}
}
history[0]=history[1];
history[1]=history[2];
history[2]=target;
}
}
Комментариев нет:
Отправить комментарий