Skip to content

Potential Field

Eduardo Makita edited this page Mar 21, 2023 · 4 revisions

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.

Como Criar uma estratégia com Campos Potenciais?

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.

Dicas

  • Uma mesma estrategia pode ter quantos self.field quiser, o importante é que no método decide 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.

Campos Potenciais Implementados