Campeonato de Futebol Simulado de Robôs 1. Regras O campeonato de futebol simulado de robôs será disputado com o auxílio de um programa simulador que emula o comportamento de duas equipes de três mini-robôs cada uma. Uma das equipes é identificada pela cor azul e a outra, pela cor amarela. Cada jogador é identificado por uma cor (ciano para o robô 0, rosa para o 1 e verde para o 2). Deste modo, cada robô possui um rótulo de duas cores: uma para identificar a equipe e a outra para identicar o jogador. Por convenção, a equipe azul joga do lado esquerdo do campo e a equipe amarela, do lado direito. O campo (preto) tem dimensões de 150cm de largura por 130cm de altura. A bola (laranja) tem 4cm de diâmetro. Para mover a bola, os jogadores devem empurrá-la. Os jogadores são robôs retangulares, com 7,5cm de lado. Cada robô tem duas rodas, controladas por motores independentes. Quando os dois motores giram na mesma velocidade e no mesmo sentido, o robô se move linearmente para frente. Quando os dois motores giram na mesma velocidade e em sentidos opostos, o robô gira sobre si mesmo. O sentido de giro dos motores é controlado pela sua tensão de alimentação, enviada pelo programa de controle da equipe. Com uma tensão de +1.0 (ou seja, de +100%), o motor gira à velocidade máxima no sentido de fazer o robô andar para a frente; a tensão de -1.0 (-100%) corresponde à velocidade máxima para trás; e uma tensão nula mantém o motor parado. Há uma saturação nas tensões: não são possíveis tensões de valor absoluto maior que 1.0. O jogo é uma versão bastante simplificada do futebol tradicional. Não há pênaltis, faltas ou impedimentos. Também não há escanteio, lateral ou tiro de meta, pois o campo tem uma parede lateral que impede a bola de sair. Todos os jogadores têm as mesmas funções, não havendo um jogador com atribuição fixa de goleiro. O gol é marcado quando a bola entra na área da trave que existe nos lados do campo. A trave tem 40 cm de altura. Ao ser marcado um gol, os jogadores retornam a sua posição inicial predefinida. Cada equipe deverá trazer um computador, dotado de placa de rede Ethernet e podendo ser configurado manualmente para um endereço IP fixado. Uma vez iniciada a partida, o jogo deverá se desenrolar de forma totalmente autônoma (sem interferência humana via teclado, mouse, etc.). As máquinas das equipes (clientes) deverão se conectar a uma máquina servidora, sob a responsabilidade da organização do campeonato, de acordo com o protocolo especificado nesta regra. O estado atual do jogo (posições dos jogadores e bola) é mantido pelo servidor e comunicado aos clientes, com a periodicidade e o formato especificados. As máquinas cli-
ente deverão levar em conta este estado para decidir sobre as ações a serem tomadas (ou seja, quais tensões aplicar nos motores). Estas ações devem ser comunicadas ao servidor, também seguindo o protocolo padrão. As ações dos jogadores alteram o estado do jogo, que é calculado pelo servidor e informado aos clientes, iniciando um novo ciclo. As equipes podem utilizar qualquer técnica ou algoritmo que desejarem para resolver o problema. O formato de disputa dos Campeonatos (todos contra todos, grupos, eliminatório, etc.) será definido em função do número de inscritos e divulgado posteriormente (pouco antes do início do Campeonato). 2. Servidor Um programa servidor se comunicará com os programas clientes das equipes. As equipes não precisam nem podem desenvolver ou alterar o programa servidor, que é detalhado apenas para que as equipes possam testar seus programas cliente. A comunicação entre o servidor e os clientes se encarregará das seguintes ações: informar o cliente sobre o estado do jogo (placar e posição dos jogadores e da bola); receber do cliente as tensões a serem aplicadas aos motores dos seus jogadores. A comunicação entre o servidor e os clientes é feita via rede, usando sockets UDP (orientados a datagramas). A conexão com os sockets se dá nas portas 12228 (0x3000) para a equipe amarela e 16384 (0x4000) para a equipe azul. O protocolo inicial de comunicação é o seguinte: São abertos pelo servidor dois sockets UDP, nas portas 0x3000 e 0x4000, que passam a esperar por conexões. Embora os sockets sejam orientados a datagramas, definiu-se um procedimento de conexão, que envolve o envio de uma mensagem inicial padronizada, sem a qual os dados não são aceitos. O servidor aceita no máximo uma conexão em cada porta. O jogo se inicia logo após o lançamento do simulador, mesmo que ainda não estejam estabelecidas conexões nas duas portas. Uma vez iniciada a simulação, a cada período de amostragem (0.1 segundos = 100 milissegundos) o servidor repete o seguinte procedimento, até que a simulação seja encerrada: Lê todos os eventuais valores de tensões que tenham sido enviados pelos clientes desde a última amostragem; caso haja mais de um, apenas o último será considerado. As tensões são transmitidas dos programas clientes para o servidor em estruturas de dados do tipo SINAL_RADIO. Cada SINAL_RADIO contém também uma id, que é comparado com a id do último estado do jogo transmitido (ver a seguir) para advertir caso os sinais de tensão dos clientes estejam chegando atrasados.
Simula o comportamento dinâmico dos robôs e da bola desde o último instante de amostragem até o instante presente, utilizando o último valor disponível para cada uma das tensões dos motores. O servidor envia por socket o estado atual do jogo para os jogadores que estejam conectados. Este estado é descrito por uma estrutura de dados do tipo SITUACAO e contém as posições dos robôs e da bola, o placar e o estado do jogo (ativo, suspenso, etc.). A mesma informação é escrita em uma memória compartilhada, de onde pode ser lida por um programa de visualização gráfica do estado do jogo. Na estrutura SITUACAO existe também uma id, que é um número seqüencial incrementado a cada período de amostragem que permite aos clientes verificarem que não perderam nenhum quadro. Ao calcular e enviar valores para as tensões dos motores, o cliente deve retornar a id da SITUACAO com a qual estas tensões foram calculadas. 3. Visualizador O programa visualizador é responsável por ler as informações sobre o estado do jogo de uma memória compartilhada, onde o servidor as escreveu, e exibi-las na tela. Para evitar problemas de acesso simultâneo à memória compartilhada pelo servidor e pelo visualizador, o acesso é protegido por um semáforo de exclusão mútua. 4. Cliente Cada equipe deverá desenvolver seu próprio programa cliente, que conterá a sua estratégia de jogo. O algoritmo inicial a ser seguido é o seguinte: O programa pergunta ao usuário: o endereço IP ou nome da máquina onde está rodando o programa servidor; e com qual cor o usuário vai jogar (azul ou amarelo). Com estas informações, o cliente deve se conectar à porta adequada (0x0300 ou 0x0400) na máquina onde está rodando o servidor. Sendo estabelecida a conexão, o programa cliente passa a executar o seguinte procedimento, até que o usuário ou o simulador encerre a partida: Espera que o servidor envie o estado do jogo (tipo SITUACAO); caso haja mais de um dado disponível, lê todos e considera apenas o mais recente (a ocorrência freqüente deste fato indica que o programa cliente é muito complexo e não está conseguindo efetuar todo seu processamento no período de amostragem de 100ms). Com base na situação do jogo, calcula as tensões dos motores dos seus jogadores. Este cálculo geralmente (embora não obrigatoriamente) é dividido nas seguintes fases: Estratégia: decide a nova posição desejada para os robôs, de acordo com a tática de jogo da equipe.
Controle: calcula as tensões dos motores necessárias para que os robôs se movam para estas posições desejadas Envia para o servidor as tensões calculadas em uma estrutura do tipo SINAL_RADIO. Os passos de cálculo e envio das tensões são efetuados apenas caso o jogo esteja ativo; caso o jogo esteja suspenso, apenas o estado do jogo é lido, até que o estado volte a ser ativo. O estado do jogo faz parte da estrutura SITUACAO. 5. Os programas Para facilitar o desenvolvimento dos programas pelas equipes, estão sendo postos à disposição um programa servidor, um programa visualizador e um modelo de programa cliente. Todos os programas estão desenvolvidos em C++ para sistema operacional Linux. Os programas servidor e visualizador implementam todas as funcionalidades necessárias, correspondendo essencialmente aos programas que serão utilizados no campeonato. O programa cliente tem todas as funcionalidades de comunicação com o servidor e oferece as estruturas de dados e classes necessárias para que as equipes possam desenvolver suas estratégias. As principais classes do programa são: futdados: classe que armazena os dados principais sobre o estado do jogo e permite o intercâmbio de informação entre as outras classes. Algumas das informações armazenadas por esta classe são: cor e lado da equipe; estado do jogo (ativo, suspenso, etc.); id da última e da atual situações recebidas do servidor; placar da partida; posição dos robôs e da bola; posições desejadas para os meus robôs; tensões dos motores dos meus robôs. As demais classes são herdeiras da classe futdados e podem alterar estes dados. aquisicao: responsável por se comunicar com o servidor, ler o estado do jogo via socket e armazenar as informações nos campos apropriados da clase futdados. estrategia: calcula as posições desejadas para os robôs e armazena em futdados. Deve ser utilizada logo após aquisicao. No programa exemplo fornecido, esta classe implementa uma estratégia inoperante, que simplesmente mantém os robôs em trajetórias pré-definidas. obstaculos: classe (opcional) que eventualmente modifica as posições desejadas calculadas pela estratégia caso verifique que os movimentos resultantes levariam à colisão entre robôs. controle: calcula as tensões a serem aplicadas aos motores para levar os robôs até às posições desejadas.
transmissao: envia para o servidor, via socket, as tensões calculadas. futrobot: classe principal que herda de todas as classes anteriores. Uma das funções desta classe, main_futrobot, é o laço que deve ser executado continuamente pelo programa cliente. O programa cliente envolve duas threads (dois processos em paralelo). A thread principal oferece uma interface rudimentar com o usuário, que permite imprimir as posições do objeto e encerrar o programa. A segunda thread implementa o laço fundamental do sistema: aquisição, estratégia, desvio de obstáculos, controle e transmissão, em loop sem fim. Todas as classes e funções do programa cliente exemplo estão completas e são funcionais, exceto pela classe estrategia. Desta forma, uma equipe que quiser se basear no exemplo precisa apenas desenvolver uma estratégia de posicionamento dos robôs no campo, partindo das premissas de que as posições dos objetos são conhecidas e de que há um algoritmo de controle subjacente que se encarregará de levar os robôs até estas posições. 6.1. Instalação e utilização dos programas 1. Obtenha o arquivo futrobot.tar, disponível em ftp://ftp.dca.ufrn.br/cbrn2005/futrobot.tgz e descompacte-o. No Linux: > cd PASTA_ONDE_FOI_SALVO_O_ARQUIVO > tar xvfz futrobot.tgz > cd futrobot 2. No diretório futrobot deve existir o seguinte conteúdo: sistema.cpp, sistema.h funções de base envolvendo o sistema operacional (ler relógio, teclado, utilizar semáforos, etc.). Estes arquivos precisam ser reformulador para se desenvolver o sistema em outro sistema operacional. ssocket.cpp, ssocket.h biblioteca de utilização de sockets. Estes arquivos precisam ser reformulador para se desenvolver o sistema em outro sistema operacional. comunicacao.h, dados.h, funcoes.h, parametros.h contêm respectivamente os parâmetros da comunicação entre processos (sockets e memória compartilhada), as definições de estruturas de dados comuns, algumas funções auxiliares e os parâmetros geométricos (dimensões do campo, etc.) e dinâmicos (massa do robô, atritos, etc.) da simulação. principal/ diretório que contém o programa cliente. Há uma série de arquivos.cpp e.h, cada um deles contendo a implementação de uma das classes descrita na seção 5. simulador/ - diretório que contém o simulador dinâmico do jogo. visualizador/ - diretório que contém o visualizado gráfico do estado do jogo. 3. Para compilar os programas no Linux, execute: > cd PASTA_DO_FUTROBOT/simulador
> make > cd PASTA_DO_FUTROBOT/visualizador > make > cd PASTA_DO_FUTROBOT/principal > make 4. Execute o programa simulador. No Linux, abra um terminal de comandos, vá para o diretório futrobot/simulador e execute: >./simulador 5. Execute o programa visualizador. No Linux, abra um terminal de comandos, vá para o diretório futrobot/visualizador e execute: >./visualizador A execução do programa visualizador não é essencial. Tanto o simulador quanto os clientes podem funcionar sem que ele esteja sendo executado, e seu funcionamento pode ser interrompido a qualquer instante durante o decorrer da partida sem afetar o jogo. 6. Execute duas instâncias do programa cliente, que podem estar na mesma máquina ou em máquinas diferentes. O ideal é que o simulador e o visualizador sejam executados em uma máquina e cada instância do programa cliente em outra máquina, para se dispor da capacidade máxima de processamento. No Linux, abra um terminal de comandos para cada instância, vá para o diretório futrobot/visualizador e execute: >./futrobot SERVIDOR onde SERVIDOR é o nome ou endereço IP da máquina onde está rodando o servidor. Em uma das instâncias, escolha jogar com a equipe azul; na outra, com a equipe amarela. Pode-se executar apenas uma das instâncias, de modo que apenas uma das equipes se movimente.