-
Notifications
You must be signed in to change notification settings - Fork 7
Potential Field
Campos Potenciais (ou potential-fields) é uma estratégia de path planning comum no ambiente de robôs moveis. Ela consiste em criarmos um campo vetorial F(x, y) = u, v
onde x, y, t
é a posição atual do meu robô, F
é o campo potencial e u, v
são os vetores velocidade.
A implementação atual de campos potenciais no NeonFC consiste em um sistema de somatório de diversos campos que podem simultaneamente influenciar a atuação do robô, tendo diversas definições de campos, como campos de ponto, linha e campos tangenciais.
Você deve primeiro usar um template vazio de um objeto de estratégia, é importante que ele seja uma classe filha de BaseStrategy.Strategy
. Da seguinte forma:
from algorithms import PotentialField, PointField, LineField
from strategy.BaseStrategy import Strategy
class ExampleStrategy(Strategy):
def __init__(self, match):
super().__init__(match)
def start(self, robot=None):
super().start(robot=robot)
def reset(self, robot=None):
super().reset()
if robot:
self.robot = robot
def decide(self):
return 0, 0
Agora, podemos instanciar um objeto base no nosso método construtor, esse objeto base sera um PotentialField
vazio, ele servira apenas para adicionarmos os diferentes campos que queremos que trabalhem em conjunto.
def __init__(self, match):
super().__init__(match)
self.field = PotentialField(
self.match,
name=f"{self.__class__}|FieldBehaviour"
)
Com isso, podemos, no método start
adicionar campos a esse objeto self.field
. Para entender como criar cada campo procure pelas devidas documentações contidas nessa wiki. Para facilitar, iremos adicionar dois campos simples, um PointField
apontando para a bola e uma LineField
impedindo dele entrar na pequena área.
def start(self, robot=None):
super().start(robot=robot)
self.field.add_field(
PointField(
self.match,
target = lambda m: (m.ball.x, m.ball.y),
radius = 0.25, # 25 cm
decay = lambda x: x**2,
field_limits = [0.75*2 , 0.65*2],
multiplier = 0.5 # 50 cm/s
)
)
self.field.add_field(
LineField(
self.match,
target = (0, 0.650),
theta = math.pi/2,
line_size = 0.25,
line_size_max = 0.25,
line_dist = 0.25,
line_dist_max = 0.25,
line_dist_single_side = True,
decay = lambda x: (-x**2) +1,
multiplier = 0.8
)
)
Por fim, no metodo decide, precisamos computar, para uma dada posição x, y
as velocidades que serão enviadas, então teremos:
def decide(self):
behaviour = self.field
return behaviour.compute([self.robot.x, self.robot.y])
O método compute, do objeto behaviour (que atribuimos como o nosso field) já será encarregado de fazer o cálculo e enviar as velocidades vx, vy
.
-
Uma mesma estrategia pode ter quantos
self.field
quiser, o importante é que no métododecide
você crie uma heurística que escolha qual será executado para cada caso. -
Lembre-se que caso dois campos operem na mesma região, eles irão se somar! O que pode acarretar em velocidades muito maiores do que você inicialmente desejava ou em espaços no campo onde o somatório zera, resultando no robô parado!
-
Considere que haverão outros robôs em campo e também as paredes, considere se o campo potencial que você esta construindo é possível, se possível teste a exaustão!
-
O arquivo pfScratch.py é um molde inicial para desenvolver campos potenciais e tem documentação auxiliar a esta.