diff --git a/new_scripts/Agente.py b/new_scripts/Agente.py index bc1a466..563b285 100644 --- a/new_scripts/Agente.py +++ b/new_scripts/Agente.py @@ -8,11 +8,14 @@ """ from sklearn.linear_model import LinearRegression from .Geometria import Ponto +from .Campo import Campo +import math as m class Agente(object): def __init__(self, ponto = Ponto()): self.__ponto = ponto + self.__theta = 0 self.__posicoesAntigas = list() @property @@ -21,8 +24,10 @@ def ponto(self): @ponto.setter def ponto(self, value): - self._changePosition() + self.__changePosition() self.__ponto = value + c = Campo() + c.occupy(c.transform2Grid((value.x, value.y)), self) @property def posicao(self): @@ -30,21 +35,37 @@ def posicao(self): @posicao.setter def posicao(self, value): - self._changePosition() + self.__changePosition() self.ponto.posicao = value + c = Campo() + c.occupy(c.transform2Grid(value), self) @property def x(self): return self.ponto.x + + @property + def y(self): + return self.ponto.y + + @property + def theta(self): + return self.__theta + + @theta.setter + def theta(self, value): + self.__theta = value @property def posicoesAntigas(self): return self.__posicoesAntigas.copy() - def _changePosition(self): - if(len(self.__posicoesAntigas) >= 5): + def __changePosition(self): + if len(self.__posicoesAntigas) >= 5: self.__posicoesAntigas.pop(0) self.__posicoesAntigas.append(Ponto(self.ponto.x, self.ponto.y)) + c = Campo() + c.release(c.transform2Grid(self.posicao)) def predicaoAdaptativa(self): pass \ No newline at end of file diff --git a/new_scripts/Aliado.py b/new_scripts/Aliado.py index 1230c42..2e97b5f 100644 --- a/new_scripts/Aliado.py +++ b/new_scripts/Aliado.py @@ -17,8 +17,8 @@ class Aliado(Jogador): - def __init__(self, idJ, ponto = Ponto(), comportamento = COMPORTAMENTOS.DEFESA): - Jogador.__init__(id = idJ, ponto = ponto) + def __init__(self, idJ, ponto = Ponto(), comportamento = None): + Jogador.__init__(self, idJ = idJ, ponto = ponto) self.comportamento = comportamento """ Nome da função : comportamento (getter) @@ -52,4 +52,7 @@ def comportamento(self, comportamento): Retorno : Boolean : Sempre False """ def isInimigo(self): - return False \ No newline at end of file + return False + + def definirObjetivo(self, mundo): + return self.__comportamento.definirObjetivo(self, mundo) \ No newline at end of file diff --git a/new_scripts/Ball.py b/new_scripts/Ball.py index 175d401..f97941f 100644 --- a/new_scripts/Ball.py +++ b/new_scripts/Ball.py @@ -8,8 +8,12 @@ """ from .Agente import Agente from .Geometria import Ponto +from .Patterns.Singleton import Singleton -class Ball(Agente): +class Ball(Agente, Singleton): - def __init__(self, ponto = Ponto()): + def __init__(self, *args, **keyargs): + pass + + def inicializa(self, ponto = Ponto()): Agente.__init__(self, ponto) diff --git a/new_scripts/Campo.py b/new_scripts/Campo.py new file mode 100644 index 0000000..2e5e579 --- /dev/null +++ b/new_scripts/Campo.py @@ -0,0 +1,39 @@ +""" Nome do módulo : Campo + Ano de criação : 2019/10 + Descrição do módulo : Modelar o campo do jogo + Versão : 1.0 + Pré-requisitos : WeightedGridGraph + Pattern.Singleton + Membros : Lorena B Bassani +""" +from .Patterns.Singleton import Singleton +from .PathPlanning.Graph import WeightedGridGraph + + +class Campo(WeightedGridGraph, Singleton): + + def __init__(self, *args, **keyargs): + pass + + def inicializa(self, celulasX, celulasY, dimX = 150, dimY = 130): + if not hasattr(self, "grade"): + WeightedGridGraph.__init__(self, celulasX, celulasY) + self.__h = (dimX/(celulasX - 1), dimY/(celulasY - 1)) + + @property + def tamanhoCelula(self): + return self.__h + + def transform2Cart(self, cel): + # TODO : Ver Se as grades possuem as mesmas características de crescimento de coordenadas + i, j = WeightedGridGraph.transform2Cart(self, cel) + return (i*self.__h[0], j*self.__h[1]) + + def transform2Grid(self, cel): + # TODO : Redefinir trasnformação + x, y = cel + return WeightedGridGraph.transform2Grid(self, (x//self.__h[0], y//self.__h[1])) + + def cost(self, start, goal): + # TODO : Redefinir custo para variar com a proximidade a um obstáculo + return WeightedGridGraph.cost(self, start, goal) \ No newline at end of file diff --git a/new_scripts/ComportamentosJogadores/ComportamentoAtacante.py b/new_scripts/ComportamentosJogadores/ComportamentoAtacante.py index 8e409af..de04a24 100644 --- a/new_scripts/ComportamentosJogadores/ComportamentoAtacante.py +++ b/new_scripts/ComportamentosJogadores/ComportamentoAtacante.py @@ -3,10 +3,41 @@ Descrição do módulo : Comportamento de Atacante para Jogadores Versão : 1.0 Pré-requisitos : IComportamento + Geometria + Mundo, Arena, Lado + Jogador + Ball + math Membros : Lorena Bassani """ from .IComportamento import IComportamento +from ..Geometria import Ponto +from ..Mundo import Mundo, Arena, Lado +from ..Jogador import Jogador +from ..Ball import Ball +import math as m class ComportamentoAtacante(IComportamento): def __init__(self): - IComportamento.__init__(self) \ No newline at end of file + IComportamento.__init__(self) + + def definirObjetivo(self, jogador : Jogador, mundo : Mundo): + ball = mundo.ball + if ball.ponto.distancia(jogador.ponto) > 30: + x, y = ball.posicao + # Se posicionar antes da bola + if mundo.lado == Lado.DIREITO: + x += 3.35 + else: + x -= 3.35 + # Se a bola estiver acima do meio de campo, se posicionar acima dela + if y < Arena.marcacoes["Meio"].y: + y -= 3.35 + else: + y += 3.35 + return Ponto(x, y) + elif ball.ponto.distancia(jogador.ponto) > 5: + return ball.ponto + else: + resp = Arena.golEsquerdo["Meio"] if mundo.lado == Lado.ESQUERDO else Arena.golDireito["Meio"] + return resp \ No newline at end of file diff --git a/new_scripts/ComportamentosJogadores/ComportamentoDefesa.py b/new_scripts/ComportamentosJogadores/ComportamentoDefesa.py index b473344..5fdeaa1 100644 --- a/new_scripts/ComportamentosJogadores/ComportamentoDefesa.py +++ b/new_scripts/ComportamentosJogadores/ComportamentoDefesa.py @@ -3,10 +3,23 @@ Descrição do módulo : Comportamento de Defesa para Jogadores Versão : 1.0 Pré-requisitos : IComportamento + Geometria + Mundo, Arena, Lado + Jogador + Ball + math Membros : Lorena Bassani """ from .IComportamento import IComportamento +from ..Geometria import Ponto +from ..Mundo import Mundo, Arena, Lado +from ..Jogador import Jogador +from ..Ball import Ball +import math as m class ComportamentoDefesa(IComportamento): def __init__(self): - IComportamento.__init__(self) \ No newline at end of file + IComportamento.__init__(self) + + def definirObjetivo(self, jogador, mundo): + pass \ No newline at end of file diff --git a/new_scripts/ComportamentosJogadores/ComportamentoGoleiro.py b/new_scripts/ComportamentosJogadores/ComportamentoGoleiro.py index e7b32d7..371ae3d 100644 --- a/new_scripts/ComportamentosJogadores/ComportamentoGoleiro.py +++ b/new_scripts/ComportamentosJogadores/ComportamentoGoleiro.py @@ -1,12 +1,63 @@ """ Nome do módulo : ComportamentoGoleiro Ano de criação : 2019/10 Descrição do módulo : Comportamento de Goleiro para Jogadores - Versão : 1.0 + Versão : 2.0 Pré-requisitos : IComportamento + Geometria + Mundo, Arena, Lado + Ball + Jogador + math Membros : Lorena Bassani """ from .IComportamento import IComportamento +from ..Geometria import Ponto +from ..Mundo import Mundo, Arena, Lado +from ..Ball import Ball +from ..Jogador import Jogador +import math as m class ComportamentoGoleiro(IComportamento): def __init__(self): - IComportamento.__init__(self) \ No newline at end of file + IComportamento.__init__(self) + + def definirObjetivo(self, jogador : Jogador, mundo : Mundo): + """ Ideia da implementação : + Posicionar o robô de forma que ele impessa a trajetória da bola + Como : Calcular o angulo de abertura entre a bola e o gol + Posicionar o robô onde o "triangulo" tenha base de 7,5 (tamanho do robô) + """ + resp = Ponto() + ball = mundo.ball + bx, _ = ball.posicao + bt = ball.theta + """ a² = b² + c² - 2bc*cos α + a² - b² - c² = -2bc* cos α + (b² + c² - a²)/2bc = cos α + α = acos(((b² + c² - a²)/2bc)) + Onde : + a <- lado oposto (tamanho do gol) + b e c <- lados adjascentes (distancia da bola até um dos limites do gol) + α <- angulo desejado + """ + gol = Arena.golDireito if mundo.lado == Lado.DIREITO else Arena.golEsquerdo + a = Arena.metricas["Gol"][1] + b = ball.ponto.distancia(gol["Superior"]) + c = ball.ponto.distancia(gol["Inferior"]) + alpha = (b**2 + c**2 - a**2)/2*b*c + if alpha > 1: + alpha = 1.0 + elif alpha < -1: + alpha = -1.0 + alpha = m.acos(alpha) + + dx = 3.75/m.tan(alpha) if m.tan(alpha) != 0 else 0 # 3.75 é metade da largura do robô de 7.5x7.5 + resp.x = bx + dx if mundo.lado == Lado.DIREITO else bx - dx + + theta = m.fabs(bt - jogador.theta) + resp.y = (resp.x/m.tan(theta)) + + resp.y = 100 if resp.y > 100 else 30 if resp.y < 30 else resp.y + resp.posicao = (10, 65) if mundo.lado == Lado.ESQUERDO and resp.x > 37.5 else (150, 65) if mundo.lado == Lado.DIREITO and resp.x < 112.5 else resp.posicao + + return resp \ No newline at end of file diff --git a/new_scripts/ComportamentosJogadores/ComportamentoLissajous.py b/new_scripts/ComportamentosJogadores/ComportamentoLissajous.py new file mode 100644 index 0000000..f51d6ec --- /dev/null +++ b/new_scripts/ComportamentosJogadores/ComportamentoLissajous.py @@ -0,0 +1,36 @@ +""" Nome do módulo : ComportamentoLissajous + Ano de criação : 2019/10 + Descrição do módulo : Modela um comportamento que descreve uma curva de Lissajous + Versão : 1.0 + Pré-requisitos : IComportamento + Geometria + math + Membros : Lorena B Bassani +""" +from .IComportamento import IComportamento +from ..Geometria import Ponto +from ..Mundo import Mundo, Arena, Lado +from ..Jogador import Jogador +from ..Ball import Ball +import math as m + +class ComportamentoLissajous(IComportamento): + __PI = 3.14159 + def __init__(self, A = 30, B = 100, a = 3, b = 4, sig = (__PI/2)): + IComportamento.__init__(self) + self.A = A + self.B = B + self.a = a + self.b = b + self.sigma = sig + self.__t = 0 + + def definirObjetivo(self, jogador, Mundo): + """ Na matemática, a curva de Lissajous (figura de Lissajous ou curva de Bowditch) + é o gráfico produzido por um sistema de equações paramétricas que descreve um complexo movimento harmônico. + x = A*sen(at + sig), y = B*sen(bt) + """ + x = self.A*m.sin(self.a*self.__t + self.sigma) + y = self.B*m.sin(self.b*self.__t) + self.__t += 1 + return Ponto(x, y) \ No newline at end of file diff --git a/new_scripts/ComportamentosJogadores/Factory.py b/new_scripts/ComportamentosJogadores/Factory.py index 73ce480..bb93df4 100644 --- a/new_scripts/ComportamentosJogadores/Factory.py +++ b/new_scripts/ComportamentosJogadores/Factory.py @@ -12,6 +12,7 @@ from .ComportamentoGoleiro import ComportamentoGoleiro from .ComportamentoDefesa import ComportamentoDefesa from .ComportamentoAtacante import ComportamentoAtacante +from .ComportamentoLissajous import ComportamentoLissajous class Factory(object): @@ -28,5 +29,7 @@ def create(comportamento): return ComportamentoGoleiro() elif comportamento == COMPORTAMENTOS.ATACANTE: return ComportamentoAtacante() + elif comportamento == COMPORTAMENTOS.DEFESA: + return ComportamentoDefesa() else: - return ComportamentoDefesa() \ No newline at end of file + return ComportamentoLissajous() \ No newline at end of file diff --git a/new_scripts/ComportamentosJogadores/IComportamento.py b/new_scripts/ComportamentosJogadores/IComportamento.py index 786f7c2..b7ff0a2 100644 --- a/new_scripts/ComportamentosJogadores/IComportamento.py +++ b/new_scripts/ComportamentosJogadores/IComportamento.py @@ -6,4 +6,5 @@ Membros : Lorena Bassani """ class IComportamento(object): - pass \ No newline at end of file + def definirObjetivo(self, jogador, mundo): + raise NotImplementedError \ No newline at end of file diff --git a/new_scripts/Controle/ControleTrajeto/ControlePID.py b/new_scripts/Controle/ControleTrajeto/ControlePID.py new file mode 100644 index 0000000..bb3cb88 --- /dev/null +++ b/new_scripts/Controle/ControleTrajeto/ControlePID.py @@ -0,0 +1,87 @@ +import time +from .IControleTrajeto import IcontroleTrajeto +class ControleTrajetoPID(IcontroleTrajeto): + def __init__(self, P = 0.2, I = 0.0, D = 0.0, current_time=None): + """Determines how aggressively the PID reacts to the current error with setting Proportional Gain""" + self.Kp = P + """Determines how aggressively the PID reacts to the current error with setting Integral Gain""" + self.Ki = I + """Determines how aggressively the PID reacts to the current error with setting Derivative Gain""" + self.Kd = D + + self.sample_time = 0.00 + self.current_time = current_time if current_time is not None else time.time() + self.last_time = self.current_time + + self.clear() + + def clear(self): + """Clears PID computations and coefficients""" + self.SetPoint = 0.0 + + self.PTerm = 0.0 + self.ITerm = 0.0 + self.DTerm = 0.0 + self.lastError = 0.0 + + # Windup Guard + self.intError = 0.0 + self.windupGuard = 20.0 + + self.output = 0.0 + + def controle(self, actualValue): + pass + """ xs, ys, ts = start + xg, yg, tg = goal + erroT = ts - tg + erroX = xs - xg + erroY = ys - yg """ + + def update(self, feedback_value, current_time=None): + """ Calculates PID value for given reference feedback + Test PID with Kp=1.2, Ki=1, Kd=0.001 (test_pid.py) + """ + error = self.SetPoint - feedback_value + + self.current_time = current_time if current_time is not None else time.time() + delta_time = self.current_time - self.last_time + deltaError = error - self.lastError + + if (delta_time >= self.sample_time): + self.PTerm = self.Kp * error + self.ITerm += error * delta_time + + if (self.ITerm < -self.windupGuard): + self.ITerm = -self.windupGuard + elif (self.ITerm > self.windupGuard): + self.ITerm = self.windupGuard + + self.DTerm = 0.0 + if delta_time > 0: + self.DTerm = deltaError / delta_time + + # Remember last time and last error for next calculation + self.last_time = self.current_time + self.lastError = error + + self.output = self.PTerm + (self.Ki * self.ITerm) + (self.Kd * self.DTerm) + + def setWindup(self, windup): + """ Integral windup, also known as integrator windup or reset windup, + refers to the situation in a PID feedback controller where + a large change in setpoint occurs (say a positive change) + and the integral terms accumulates a significant error + during the rise (windup), thus overshooting and continuing + to increase as this accumulated error is unwound + (offset by errors in the other direction). + The specific problem is the excess overshooting. + """ + self.windupGuard = windup + + def setSampleTime(self, sample_time): + """ PID that should be updated at a regular interval. + Based on a pre-determined sampe time, the PID decides + if it should compute or return immediately. + """ + self.sample_time = sample_time diff --git a/new_scripts/Controle/ControleTrajeto/ControleSiegwart.py b/new_scripts/Controle/ControleTrajeto/ControleSiegwart.py new file mode 100644 index 0000000..030bcdb --- /dev/null +++ b/new_scripts/Controle/ControleTrajeto/ControleSiegwart.py @@ -0,0 +1,46 @@ +from .IControleTrajeto import IcontroleTrajeto +from ...Geometria import Ponto, to180range +import math as m + +class ControleSiegwart(IcontroleTrajeto): + + __kRho = 1.85 + __kAlpha = 9.7 + __kBeta = -0.01 + __PI = 3.14159 + + def controle(self, actualValue, objective, speed): + xa, ya, ta = actualValue + xo, yo, to = objective + + ta = to180range(ta*ControleSiegwart.__PI/180) + rho = Ponto(xa, ya).distancia(Ponto(xo, yo)) + lamb = m.atan2(yo - ya, xo - xa) + + if rho < 3: + lamb = 0 + + alpha = to180range(lamb - ta) + beta = to - lamb + + linearSpeed = - ControleSiegwart.__kRho*rho + angularSpeed = ControleSiegwart.__kAlpha*alpha + ControleSiegwart.__kBeta*beta + + scale = speed/linearSpeed + linearSpeed *= scale + angularSpeed *= scale + + if rho < 3: + linearSpeed = 0 + angularSpeed *= 0.4 + + if m.fabs(alpha) > 0.5*ControleSiegwart.__PI: + linearSpeed = - linearSpeed + + result = ((linearSpeed - angularSpeed*3.35)/2, (linearSpeed + angularSpeed*3.35)/2) + maxSpeed = max(m.fabs(result[0]), m.fabs(result[1])) + + if maxSpeed > 100: + result = (result[0]*100/m.fabs(maxSpeed), result[1]*100/m.fabs(maxSpeed)) + + return result \ No newline at end of file diff --git a/new_scripts/Controle/ControleTrajeto/IControleTrajeto.py b/new_scripts/Controle/ControleTrajeto/IControleTrajeto.py new file mode 100644 index 0000000..dbb5888 --- /dev/null +++ b/new_scripts/Controle/ControleTrajeto/IControleTrajeto.py @@ -0,0 +1,4 @@ +class IcontroleTrajeto(object): + + def controle(self, actualValue, objective): + raise NotImplementedError \ No newline at end of file diff --git a/new_scripts/Controle/ControleTrajeto/__init__.py b/new_scripts/Controle/ControleTrajeto/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/new_scripts/Controle/ControleVelocidade/__init__.py b/new_scripts/Controle/ControleVelocidade/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/new_scripts/Controle/__init__.py b/new_scripts/Controle/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/new_scripts/Geometria.py b/new_scripts/Geometria.py index 5f0f55d..a250150 100644 --- a/new_scripts/Geometria.py +++ b/new_scripts/Geometria.py @@ -68,4 +68,12 @@ def __eq__(self, outro): """ def distancia(self, outro): return m.sqrt((self.x - outro.x)**2 + (self.y - outro.y)**2) - \ No newline at end of file + +def to180range(angle): + M_PI = 3.14159 + angle = m.fmod(angle, 2 * M_PI) + if (angle < - M_PI): + angle = angle + 2 * M_PI + elif (angle > M_PI): + angle = angle - 2 * M_PI + return angle \ No newline at end of file diff --git a/new_scripts/Inimigo.py b/new_scripts/Inimigo.py index 860d04d..75f4ef4 100644 --- a/new_scripts/Inimigo.py +++ b/new_scripts/Inimigo.py @@ -12,7 +12,7 @@ class Inimigo(Jogador): def __init__(self, idJ, ponto = Ponto()): - Jogador.__init__(self, id = idJ, ponto = ponto) + Jogador.__init__(self, idJ = idJ, ponto = ponto) """ Nome da função : isInimigo Intenção da função : Dizer se um Jogador é Inimigo diff --git a/new_scripts/Jogador.py b/new_scripts/Jogador.py index d8ad357..b623a6a 100644 --- a/new_scripts/Jogador.py +++ b/new_scripts/Jogador.py @@ -12,7 +12,7 @@ class Jogador(Agente): def __init__(self, idJ, ponto = Ponto()): - Agente.__init__(ponto) + Agente.__init__(self, ponto) self.__id = idJ """ Nome da função : id (getter) diff --git a/new_scripts/Mundo.py b/new_scripts/Mundo.py index 9eba45f..04e8980 100644 --- a/new_scripts/Mundo.py +++ b/new_scripts/Mundo.py @@ -9,15 +9,55 @@ Membros : Lorena Bassani """ from .Patterns.Singleton import Singleton +from .Geometria import Ponto from .Jogador import Jogador from .ComportamentosJogadores.Comportamentos import COMPORTAMENTOS from .Ball import Ball +from .Campo import Campo +from .Controle.ControleTrajeto.IControleTrajeto import IcontroleTrajeto +from .Controle.ControleTrajeto.ControleSiegwart import ControleSiegwart +from .PathPlanning.IPathPlanning import IPathPlanning +from .PathPlanning.AStar import AStar +from enum import Enum +import math as m + +class Lado(Enum): + ESQUERDO = 0 + DIREITO = 1 + +class Arena(object): + cantoSuperior = { "Direito" : Ponto(170, 0), + "Esquerdo" : Ponto(0, 0) + } + cantoInferior = { "Direito" : Ponto(170, 130), + "Esquerdo" : Ponto(0, 130) + } + golDireito = { "Superior" : Ponto(160 ,45), + "Meio" : Ponto(160, 65), + "Inferior" : Ponto(160, 95) + } + golEsquerdo = { "Superior" : Ponto(10 ,45), + "Meio" : Ponto(10, 65), + "Inferior" : Ponto(10, 95) + } + marcacoes = { "Meio" : Ponto(85, 65) + } + metricas = { "Tamanho " : (170, 130), + "Gol" : (10, 40) + } class Mundo(Singleton): - def __init__(self, ball): - Singleton.__init__(self) + + def __init__(self, *args, **keyargs): + pass + + def inicializa(self, controladorTrajeto = ControleSiegwart(), pathPlanning = AStar, lado = Lado.DIREITO): self.__jogadores = {"Team" : list(), "Enemies" : list()} - self.__ball = ball + self.ball = Ball() + self.campo = Campo(celulasX = 15, celulasY = 13) + self.pathPlanning = AStar + self.controladorTrajeto = controladorTrajeto + self.lado = lado """ Nome da função : inimigos (getter) Intenção da função : Retorna os Inimigos @@ -64,20 +104,53 @@ def goleiro(self): Retorno : Nenhum """ @goleiro.setter - def goleiro(self, playerId): + def goleiro(self, jogadorId): if not self.goleiro: - p = player(playerId) + p = self.jogador(jogadorId) p.comportamento = COMPORTAMENTOS.GOLEIRO - """ Nome da função : player (getter) + """ Nome da função : jogador (getter) Intenção da função : Retornar um Jogador de Acordo com seu Id Pré-requisitos : Nenhum Efeitos colaterais : Nenhum Parâmetros : int : Id do Jogador Retorno : Jogador : Jogador correspondente ao Id """ - def player(self, playerId): - p = list(filter(lambda x: x.id == playerId, self.__jogadores["Team"])) + def jogador(self, jogadorId): + p = list(filter(lambda x: x.id == jogadorId, self.__jogadores["Team"])) if p: return p return None + + @property + def time(self): + return self.__jogadores["Team"] + + @time.setter + def time(self, newTime): + self.__jogadores["Team"].clear() + self.__jogadores["Team"].extend(newTime) + + def control(self): + self.__defineFunction() + controle = list() + for p in self.__jogadores["Team"]: + # Primeiro passo: Definir Objetivo + goal = p.definirObjetivo(self).posicao + start = p.posicao + # Segundo passo: Planejar Caminho + # path = self.pathPlanning.PathPlan(self.campo, self.campo.transform2Grid(start), self.campo.transform2Grid(goal)) + # path = self.pathPlanning.reconstructPath(path, self.campo.transform2Grid(start), self.campo.transform2Grid(goal)) + # Terceiro passo: Seguir Caminho + # gx, gy = self.campo.transform2Cart(path.pop(0)) + gx, gy = goal + sx, sy = start + gt = m.acos((gx*sx + gy*sy)/(m.sqrt(gx**2 + gy**2)*m.sqrt(sx**2 + sy**2))) + goal = gx, gy, gt + start = sx, sy, p.theta + vel = self.controladorTrajeto.controle(actualValue = start, objective = goal, speed = 100) + controle.append(vel) + return controle + + def __defineFunction(self): + pass \ No newline at end of file diff --git a/new_scripts/PathPlanning/Graph.py b/new_scripts/PathPlanning/Graph.py index d7ca017..6d2584e 100644 --- a/new_scripts/PathPlanning/Graph.py +++ b/new_scripts/PathPlanning/Graph.py @@ -152,5 +152,13 @@ class WeightedGridGraph(GridGraph): def __init__(self, celulasX, celulasY): GridGraph.__init__(self, celulasX, celulasY) - def cost(self, cel1, cel2): + """ Nome da função : cost + Intenção da função : Calcula o custo de se mover de start até goal + Pré-requisitos : Nenhum + Efeitos colaterais : Nenhum + Parâmetros : int : Celula de Inicio + int : Celula de Objetivo + Retorno : int : Custo de movimentação pela grade + """ + def cost(self, start, goal): return 1 diff --git a/new_scripts/Patterns/Observer.py b/new_scripts/Patterns/Observer.py index 18939f5..75a549d 100644 --- a/new_scripts/Patterns/Observer.py +++ b/new_scripts/Patterns/Observer.py @@ -1,16 +1,54 @@ +""" Nome do módulo : Observer + Ano de criação : 2019/10 + Descrição do módulo : Interface do Padrão Observer + Versão : 1.0 + Pré-requisitos : Nenhum + Membros : Lorena B Bassani +""" + +class Observer(object): + + """ Nome da função : update + Intenção da função : Informar a ocorrencia do evento para o observador + Pré-requisitos : Desconhecido + Efeitos colaterais : Desconhecido + Parâmetros : Desconhecido + Retorno : Desconhecido + """ + def update(self, *args, **keyargs): + raise NotImplementedError + class Notifier(object): def __init__(self): self.__observers = list() + """ Nome da função : attach + Intenção da função : Inserir um observador na lista de observação + Pré-requisitos : Nenhum + Efeitos colaterais : O Observador é inserido na lista de observação + Parâmetros : Observer : Observador a ser inserido + Retorno : Nenhum + """ def attach(self, observer : Observer): self.__observers.append(observer) + """ Nome da função : dettach + Intenção da função : Retirar um Observador da lista de observação + Pré-requisitos : Observador estar na lista de observadores + Efeitos colaterais : Observador é retirado da lista de observadores + Parâmetros : Obervador : Observador a ser retirado da lista de observadores + Retorno : Nenhum + """ def dettach(self, observer: Observer): self.__observers.remove(observer) - def notify(self): - map(lambda x: x.update(), self.__observers) + """ Nome da função : notify + Intenção da função : Notificar todos os observadores + Pré-requisitos : Nenhum + Efeitos colaterais : Todos os obervadores são notificados + Parâmetros : Desconhecido + Retorno : Nenhum + """ + def notify(self, *args, **keyargs): + map(lambda x: x.update(*args, **keyargs), self.__observers) -class Observer(object): - def update(self): - raise NotImplementedError \ No newline at end of file diff --git a/new_scripts/Patterns/Singleton.py b/new_scripts/Patterns/Singleton.py index 425fd27..98b4794 100644 --- a/new_scripts/Patterns/Singleton.py +++ b/new_scripts/Patterns/Singleton.py @@ -1,14 +1,23 @@ +""" Nome do módulo : Singleton + Ano de criação : 2019/10 + Descrição do módulo : Módulo que implementa padrão Singleton + Versão : 2.0 + Pré-requisitos : Nenhum + Membros : Lorena B. Bassani +""" + class Singleton(object): - __instance = None - @staticmethod - def getInstance(): - """ Static access method. """ - if Singleton.__instance == None: - Singleton() - return Singleton.__instance - def __init__(self): - """ Virtually private constructor. """ - if Singleton.__instance != None: - raise Exception("This class is a singleton!") - else: - Singleton.__instance = self \ No newline at end of file + __single = None # the one, true Singleton + + def __new__(classtype, *args, **kwargs): + # Check to see if a __single exists already for this class + # Compare class types instead of just looking for None so + # that subclasses will create their own __single objects + if classtype != type(classtype.__single): + classtype.__single = object.__new__(classtype) + classtype.inicializa(classtype.__single, *args, **kwargs) + return classtype.__single + + def inicializa(self, *args, **keyargs): + raise NotImplementedError + diff --git a/scripts/Ball.py b/scripts/Ball.py index c11d5d0..22e50f2 100644 --- a/scripts/Ball.py +++ b/scripts/Ball.py @@ -38,7 +38,7 @@ def predict_ball_method(self, player, mundo): cy_ball_predic = self.gety() + vy_ball * k_pred * norm_v_ball return cx_ball_predic, cy_ball_predic - def predict_ball_method_ofensive(self, player): + def predict_ball_method_ofensive(self, player, mundo): mx = sum(self.x_old)/5.0 my = sum(self.y_old)/5.0 @@ -57,7 +57,7 @@ def predict_ball_method_ofensive(self, player): dif_y = self.gety()-player.gety() ro_aux = math.sqrt(dif_x**2 + dif_y**2) - c_magic = self.predicao_adaptativa(self.x) + c_magic = self.predicao_adaptativa(self.x, mundo) k_pred = c_magic*ro_aux/85.0 cx_ball_predic = self.getx() + vx_ball * k_pred * norm_v_ball diff --git a/scripts/Player.py b/scripts/Player.py index fc454e1..9e75e57 100644 --- a/scripts/Player.py +++ b/scripts/Player.py @@ -145,7 +145,7 @@ def chuta(self, world): xr, yr = self.getxy() xg, yg = world.get_right_goal() my_inf = 1e5 - ofensividade = world.campo_potencial(self) + ofensividade = self.campo_potencial(world) d_East = abs(xb - world.FIELD_RIGHT) d_West = abs(xb - world.FIELD_LEFT) @@ -167,7 +167,7 @@ def chuta(self, world): pto_inf = ((world.FIELD_RIGHT + world.FIELD_LEFT)/2, my_inf) d_Best = d_South - value = world.campo_potencial(self) + value = self.campo_potencial(world) grad_x = (world.campo_potencial_g(xb + 10.0, yb, self.medo_de_bater_na_parede) - value ) @@ -297,12 +297,12 @@ def controle(self, world): def campo_potencial(self, mundo): #return (math.tanh((xr - right_upper[0])**2/medo_de_bater_na_parede**2)* math.tanh((xr - left_upper[0])**2/medo_de_bater_na_parede**2) * math.tanh((yr - right_lower[1])**2/medo_de_bater_na_parede**2) * math.tanh((yr - right_upper[1])**2/medo_de_bater_na_parede**2))/4.0 - xr, yr = mundo.getxy() + xr, yr = self.getxy() dx = xr - mundo.left_goal[0] dy = yr - mundo.left_goal[1] ro = math.sqrt(dx**2+dy**2) - ret = (math.tanh((xr - self.right_upper[0])**2/self.medo_de_bater_na_parede**2)* math.tanh((xr - self.left_upper[0])**2/self.medo_de_bater_na_parede**2) * math.tanh((yr - self.right_lower[1])**2/self.medo_de_bater_na_parede**2) * math.tanh((yr - self.right_upper[1])**2/player.medo_de_bater_na_parede**2))/(1-math.exp(-(ro**2)/8000.0))/4.0 + ret = (math.tanh((xr - mundo.right_upper[0])**2/self.medo_de_bater_na_parede**2)* math.tanh((xr - mundo.left_upper[0])**2/self.medo_de_bater_na_parede**2) * math.tanh((yr - mundo.right_lower[1])**2/self.medo_de_bater_na_parede**2) * math.tanh((yr - mundo.right_upper[1])**2/self.medo_de_bater_na_parede**2))/(1-math.exp(-(ro**2)/8000.0))/4.0 if ro < 100: ret = 0 return ret \ No newline at end of file diff --git a/scripts/PlayerAtaque.py b/scripts/PlayerAtaque.py index 32500f4..9d381c2 100644 --- a/scripts/PlayerAtaque.py +++ b/scripts/PlayerAtaque.py @@ -14,7 +14,7 @@ def chuta(self, world): distancia_pra_sair_da_parede = 3.5 ball = world.get_ball() - xb, yb = ball.predict_ball_method_ofensive(self) + xb, yb = ball.predict_ball_method_ofensive(self, world) xg, yg = world.get_enemy_goal() adiciona_ponto(int(xb), int(yb), 127, 255, 60, 'bola') diff --git a/scripts/PlayerDefesa.py b/scripts/PlayerDefesa.py index 181ba28..e588749 100644 --- a/scripts/PlayerDefesa.py +++ b/scripts/PlayerDefesa.py @@ -61,8 +61,8 @@ def chuta(self, world): ym = yg - ygi#calculo do meio de campo Y #calculo da distancia da bola pro meio : INICIO - vec_ball_meio_x = xb - xmeioRicardo - vec_ball_meio_y = yb - ymeioRicardo + vec_ball_meio_x = xb + vec_ball_meio_y = yb norm_vec_ball_meio = math.sqrt(vec_ball_meio_x**2 + vec_ball_meio_y**2)#distancia da bola pro meio #calculo da distancia da bola pro meio : FIM ########## diff --git a/scripts/World.py b/scripts/World.py index b390c9c..b9f19f0 100644 --- a/scripts/World.py +++ b/scripts/World.py @@ -123,4 +123,13 @@ def updateField(self, fieldRight, fieldLeft, fieldTop, fieldBottom): print (self.FIELD_LEFT) print (self.FIELD_TOP) print (self.FIELD_BOTTOM) - print ("ola1") \ No newline at end of file + print ("ola1") + + def campo_potencial_g(self, xr, yr, medo_de_bater_na_parede): + #return (math.tanh((xr - right_upper[0])**2/medo_de_bater_na_parede**2)* math.tanh((xr - left_upper[0])**2/medo_de_bater_na_parede**2) * math.tanh((yr - right_lower[1])**2/medo_de_bater_na_parede**2) * math.tanh((yr - right_upper[1])**2/medo_de_bater_na_parede**2))/4.0 + dx = xr - self.right_goal[0] + dy = yr - self.right_goal[1] + ro = math.sqrt(dx**2+dy**2) + if ro < 100: + return 0 + return (math.tanh((xr - self.right_upper[0])**2/medo_de_bater_na_parede**2)* math.tanh((xr - self.left_upper[0])**2/medo_de_bater_na_parede**2) * math.tanh((yr - self.right_lower[1])**2/medo_de_bater_na_parede**2) * math.tanh((yr - self.right_upper[1])**2/medo_de_bater_na_parede**2))/(1-math.exp(-(ro**2)/8000.0))/4.0 diff --git a/simulador.py b/simulador.py index 6ce858b..f69ad9c 100644 --- a/simulador.py +++ b/simulador.py @@ -1,21 +1,12 @@ """ VSSS-o-Primeiro Nome do módulo : simulador - Ano de criação : 2019/01 - Descrição do módulo: Modulo para rodar o simulador no código do VSSS (primeira versão) - Versão: 1.0 + Ano de criação : 2019/10 + Descrição do módulo: Modulo para rodar o simulador no código do VSSS (segunda versão) + Versão: 2.0 Pré-requisitos : vsscorepy Membros: Lorena Bassani """ -import vsscorepy as simulador -import scripts as vsss_erus -from scripts.World import World -from scripts.Goalkeeper import Goalkeeper as gk -from scripts.PlayerAtaque import PlayerAtaque as fw -from scripts.PlayerDefesa import PlayerDefesa as df -from scripts.Ball import Ball -from scripts.Player import Player -from scripts.Agent import Agent from vsscorepy.communications.command_sender import CommandSender from vsscorepy.communications.debug_sender import DebugSender from vsscorepy.communications.state_receiver import StateReceiver @@ -24,7 +15,14 @@ from vsscorepy.domain.point import Point from vsscorepy.domain.pose import Pose from vsscorepy.domain.debug import Debug + +from new_scripts.Mundo import Mundo +from new_scripts.Inimigo import Inimigo +from new_scripts.Aliado import Aliado +from new_scripts.ComportamentosJogadores.Factory import COMPORTAMENTOS + from enum import Enum +import math as m class Team(Enum): BLUE = 1 @@ -53,24 +51,22 @@ def recebe_estado(self): k = kernel() -mundo = World() -team = [fw(), df(), gk()] -mundo.add_atk_player(team[0]) -mundo.add_def_player(team[1]) -mundo.add_gk_player(team[2]) -enemie = [Player(), Player(), Player()] -mundo.jogadores["Enemies"].extend(enemie) +mundo = Mundo() +time = [Aliado(0, comportamento = COMPORTAMENTOS.GOLEIRO), Aliado(1, comportamento = COMPORTAMENTOS.ATACANTE), Aliado(2)] +inimigo = [Inimigo(3), Inimigo(4), Inimigo(5)] +mundo.inimigos = inimigo +mundo.time = time while True: state = k.recebe_estado() - mundo.ball.update_position((state.ball.x, state.ball.y)) - for i in range(0, 2): + mundo.ball.posicao = (state.ball.x, state.ball.y) + mundo.ball.theta = m.atan2(state.ball.speed_y, state.ball.speed_x) + for i in range(0, len(time)): r = state.team_yellow[i] e = state.team_blue[i] - team[i].set_position_xyt(r.x, r.y, r.angle) - enemie[i].set_position_xyt(e.x, e.y, e.angle) - - listaComando = list() - for p in team: - velr, vell = p.controle(mundo) - listaComando.append(WheelsCommand(vell, velr)) - k.envia_comando(listaComando[0], listaComando[1], listaComando[2]) \ No newline at end of file + time[i].posicao = (r.x, r.y) + time[i].theta = r.angle + inimigo[i].posicao = (e.x, e.y) + inimigo[i].theta = (e.angle) + listaComando = mundo.control() + listaComando = list(map(lambda vel: WheelsCommand(vel[0], vel[1]), listaComando)) + k.envia_comando(listaComando[0], listaComando[1], listaComando[2]) diff --git a/vss-simulator/VSS-CorePy b/vss-simulator/VSS-CorePy new file mode 160000 index 0000000..b560ecd --- /dev/null +++ b/vss-simulator/VSS-CorePy @@ -0,0 +1 @@ +Subproject commit b560ecdeefb2700eb68b978eb9573574fbc2bfff