FARIAS, Rodrigo. FlighIsntructor, um instrutor de vôo virtual
Transcrição
FARIAS, Rodrigo. FlighIsntructor, um instrutor de vôo virtual
Universidade Federal de Pernambuco Centro de Informática Ciência da Computação FlightInstructor, um Instrutor de Vôo Virtual para o Microsoft Flight Simulator X Trabalho de Graduação Aluno: Rodrigo Carvalho de Farias ([email protected]) Orientadora: Judith Kelner ([email protected]) Co-orientadora: Veronica Teichrieb ([email protected]) Recife, 25 de janeiro de 2008 Resumo Para exercer a profissão comercialmente, o piloto de avião precisa possuir a licença de Piloto Comercial, que é obtida mediante um curso preparatório. Durante o curso, o aluno passa por uma etapa de treinamento em aeronaves e simuladores de vôo. Embora não consigam simular com perfeição todas as características de uma aeronave real, os simuladores de vôo têm o custo operacional inferior, permitem a prática em cenários específicos e são tolerantes às falhas do aluno. Este Trabalho de Graduação apresenta o FlightInstructor, um instrutor de vôo virtual para o Microsoft Flight Simulator X, com foco no desenvolvimento dos módulos responsáveis pela execução de procedimentos aeronáuticos relacionados ao vôo por instrumento. Cada tarefa executada pelo instrutor virtual é exibida para o aluno, como uma forma de orientá-lo na execução do procedimento. Palavras-chave: instrutor virtual, Microsoft Flight Simulator X, procedimentos aeronáuticos, SimConnect, vôo por instrumento. 2 Agradecimentos Agradeço primeiramente a Deus e seus emissários pela paz e inspiração com as quais fui agraciado durante o desenvolvimento desse trabalho, bem como em toda a minha vida. Agradeço à minha mãe, pelo seu amor incondicional e exemplo cristão, que fazem do nosso lar um porto seguro. Seu suporte, nas mais diversas áreas, foi fundamental para a conclusão deste curso. É uma grande companheira que tenho na Eternidade. Agradeço a Syldênia pelo seu amor, carinho e apoio nas decisões e momentos difíceis. É outra grande companheira que Deus colocou no meu caminho. Agradeço a todos os amigos do GPRT, sempre solícitos. Agradeço, em especial, a Mozart William, João Marcelo e Gabriel Almeida, que contribuíram diretamente no projeto. Agradeço a João Lima pelo apoio formal dado ao nosso momento Treloso de confraternização, quando nos deliciamos com os biscoitos da Vitarella. Agradeço ao Cmte. Thiago Dias, um grande amigo e referência na aviação, que também contribuiu diretamente no projeto. Agradeço à minha co-orientadora Veronica Teichrieb, pela contribuição direta no projeto, na vida profissional, e pela forma tão gentil com que nos trata. Agradeço à professora Judith Kelner, minha orientadora, e ao professor Djamel Sadok, pela excelente oportunidade de trabalhar em um ambiente tão agradável e enriquecedor como o GPRT. Agradeço, enfim, a todos os amigos e familiares que, direta ou indiretamente contribuíram no projeto. Que Deus os abençoe. 3 Sumário 1. Introdução........................................................................................................................... 5 Objetivo ........................................................................................................................... 5 Estrutura do Documento ................................................................................................. 6 2. Ensino na Aviação.............................................................................................................. 7 2.1. Processo de Ensino ........................................................................................................ 7 2.2. Vôo por Instrumento ....................................................................................................... 8 2.3. Ferramentas Relacionadas........................................................................................... 11 2.3.1. Livros ..................................................................................................................... 12 2.3.2. Cursos com Recursos Multimídia.......................................................................... 12 2.3.3. Simuladores de Sistemas Isolados ....................................................................... 12 2.3.4. Learning Center do FSX ........................................................................................ 13 2.3.5. Instrutores de Vôo Virtuais .................................................................................... 14 3. Microsoft Flight Simulator X.............................................................................................. 15 3.1. SimConnect .................................................................................................................. 17 4. FlightInstructor .................................................................................................................. 18 4.1. Domínio da Aplicação ................................................................................................... 18 4.2. SimConnect para C#..................................................................................................... 18 4.3. Módulo EasyConnect.................................................................................................... 22 4.3.1. Arquitetura ............................................................................................................. 24 4.3.2. Aplicação de Exemplo ........................................................................................... 27 4.4. Módulo ProcedurePerformer......................................................................................... 28 4.4.1. Arquitetura ............................................................................................................. 28 4.4.2. Ciclo da Aplicação ................................................................................................. 29 4.4.3. Arquivos de Configuração ..................................................................................... 32 4.5. FlightAnalyzer ............................................................................................................... 35 5. Estudo de Caso ................................................................................................................ 36 6. Conclusão......................................................................................................................... 40 6.1. Contribuições ................................................................................................................ 40 6.2. Trabalhos Futuros......................................................................................................... 41 Referências Bibliográficas........................................................................................................... 42 1.1. 1.2. 4 1. Introdução A aviação é uma área fascinante, que traz satisfação aos seus profissionais e entusiastas. Porém, os custos associados a essa atividade ainda são muito altos, restringindo seu mercado. Para exercer a profissão e ser remunerado, o piloto precisa ter a licença de Piloto Comercial de Avião (PCA), que é precedida pela licença de Piloto Privado de Avião (PPA). As escolas de aviação oferecem os cursos de PPA e PCA, que preparam o aluno para a obtenção das respectivas licenças. Os cursos são divididos em duas etapas: teórica e prática. Na etapa prática do curso de PCA, o aluno recebe instrução nas aeronaves e simuladores de vôo da escola. A instrução em simuladores de vôo durante o curso de PCA aborda basicamente os assuntos relacionados ao vôo por instrumento, onde o aluno aprende a se orientar no espaço aéreo baseado nos instrumentos de navegação da aeronave e os auxílios-rádio em terra. Os simuladores de vôo permitem que o aluno pratique em cenários específicos, criados pelo instrutor de vôo, e são tolerantes às falhas do aluno. Permitem ainda que o piloto se familiarize com os padrões operacionais da aeronave simulada, bem como com a posição dos seus instrumentos e comandos. O Microsoft Flight Simulator X (FSX) é um dos exemplos de IBM PC Based Simulator (simulador baseado em IBM PC) disponíveis no mercado, segundo a classificação sugerida por Jonathan Gabbai [1]. O FSX simula com precisão as particularidades do vôo por instrumento e permite a conexão de diversos dispositivos de interação para aumentar o grau de imersão do usuário [2]. O simulador ainda oferece uma seção dedicada ao ensino dos conceitos básicos da aviação, com material teórico e prático. Porém, o material prático é limitado a alguns exemplos isolados. 1.1. Objetivo A proposta deste trabalho de graduação é o desenvolvimento do FlightInstructor, um instrutor de vôo virtual para o FSX que complementa a etapa prática do curso de PCA, abordando alguns assuntos relacionados ao vôo por instrumento. Ele permitirá que o aluno pratique alguns conceitos aprendidos no curso sem a necessidade presencial de um instrutor de vôo. O FlightInstructor é composto pelos módulos EasyConnect, ProcedurePerformer e FlightAnalyzer. O EasyConnect é uma camada de abstração para o SimConnect, que é o protocolo de comunicação com o FSX oferecido pelo seu Software Development Kit (SDK). O ProcedurePerformer é responsável pela execução de alguns procedimentos aeronáuticos relacionados ao vôo por instrumento. Cada tarefa executada pelo instrutor virtual é exibida para o aluno, como uma forma de orientá-lo na execução do procedimento. O FlightAnalyzer, por sua vez, será responsável pela análise de um determinado procedimento executado pelo aluno, e terá como finalidade apontar seus erros e sugerir correções. No escopo deste trabalho serão apresentados os dois primeiros módulos. 5 1.2. Estrutura do Documento O capítulo 2 do presente documento descreve o processo de ensino na aviação, definindo a área de atuação da ferramenta FlightInstructor, esclarece alguns conceitos relacionados ao vôo por instrumento, e lista alguns produtos relacionados ao processo de ensino. O capítulo 3 aborda o FSX, citando algumas características do simulador, bem como do protocolo SimConnect oferecido no seu SDK. O capítulo 4 descreve o processo de desenvolvimento do FlightInstructor, exibindo a implementação dos módulos EasyConnect e ProcedurePerformer, e descrevendo conceitualmente o módulo FlightAnalyzer. O capítulo 5 explica a execução de um procedimento aeronáutico relacionado ao vôo por instrumento através de um estudo de caso. Finalmente, no capítulo 6, as principais contribuições são destacadas e os trabalhos futuros identificados são enumerados. 6 2. Ensino na Aviação As seções seguintes esclarecem alguns conceitos importantes relacionados ao processo de ensino na aviação, que servem de base para o desenvolvimento do FlightInstructor. 2.1. Processo de Ensino Para exercer a profissão e ser remunerado, o piloto precisa ter a licença de PCA, que é precedida pela licença de PPA. As escolas de aviação oferecem os cursos de PPA e PCA, que preparam o aluno para a obtenção das respectivas licenças. Os cursos são divididos em duas etapas: teórica e prática. Na etapa teórica, o aluno recebe aulas em solo e é submetido a um exame aplicado pela Agência Nacional de Aviação Civil (ANAC), para obter o Certificado de Conhecimentos Teóricos. Depois de obter o Certificado de Capacitação Física, junto ao Hospital da Aeronáutica, o aluno está apto para a etapa prática, onde recebe instrução nas aeronaves da escola. Após uma quantidade mínima de horas voadas, o aluno é submetido a um vôo, onde seus conhecimentos são verificados por um instrutor homologado pela ANAC, para, finalmente, obter a licença almejada. Na etapa prática do curso de PCA, o aluno ainda recebe instrução nos simuladores de vôo da escola. O Quadro 1 apresenta alguns valores praticados pela Escola de Aviação Civil do Aeroclube de Bauru, a título de exemplo, evidenciando o alto custo para a obtenção das licenças [3]. Quadro 1. Valores dos cursos de PPA e PCA praticados pelo Aeroclube de Bauru. Curso Piloto Privado de Avião Piloto Comercial de Avião Etapa Teórica Prática Teórica Prática (aeronave) Prática (simulador) Preço R$ 1.000,00 R$ 6.930,00 (35 horas) R$ 1.100,00 R$ 22.770,00 (115 horas) R$ 1.800,00 (40 horas) Vale ressaltar que o material didático não está incluso nos valores referentes aos cursos teóricos, e que o aluno pode voar como co-piloto, em aeronaves particulares, em troca de horas de vôo, durante a etapa prática do curso de PCA. A aeronave de treinamento usada como referência é o AB-115 Aero Boero, ilustrado na Figura 1, cuja hora de vôo custa R$ 198,00 para sócios do aeroclube, e para a compra de um pacote mínimo de 10 horas. A aeronave Cessna 172 Skyhawk é mais compatível com a realidade profissional dos pilotos, mas sua hora de vôo custa R$ 258,00 nas mesmas circunstâncias. 7 Figura 1. Cabine do AB-115 Aero Boero. O simulador de vôo referenciado é o ATC-710, cujo valor da hora de vôo é R$ 45,00, e é classificado como um Instrument Only Simulator (simulador de instrumentos), segundo Jonathan Gabbai [1]. Os simuladores de vôo permitem que o aluno pratique em cenários específicos, criados pelo instrutor de vôo, e são tolerantes às falhas do aluno. Permitem ainda que o piloto se familiarize com os padrões operacionais da aeronave simulada, bem como com a posição dos seus instrumentos e comandos. 2.2. Vôo por Instrumento A instrução em simuladores de vôo durante o curso de PCA aborda basicamente os assuntos relacionados ao vôo por instrumento, onde o aluno aprende a se orientar no espaço aéreo baseado nos instrumentos de navegação da aeronave e os auxílios-rádio em terra. É o tipo de vôo permitido quando a aeronave se encontra sob Instrument Meteorological Conditions (IMC), que determinam os limites meteorológicos entre o vôo visual e o vôo por instrumento. Quando o piloto se encontra sob IMC, precisa se submeter às Instrument Flight Rules (IFR), que são regras e limitações para esse tipo de vôo. Os procedimentos executados sob IMC são conhecidos como procedimentos IFR. Entre os procedimentos IFR existentes, pode-se citar: o Standard Instrument Departure (SID), executado logo após a decolagem de um aeroporto, durante o afastamento da aeronave; o Standard Terminal Arrival Route (STAR), durante a aproximação para um aeroporto; e o Instrument Approach Procedure (IAP), que complementa o STAR, orientando o piloto durante o pouso no aeroporto. O SID João Pessoa, do aeroporto internacional Gilberto Freyre, em Recife, é ilustrado na Figura 2. 8 Figura 2. SID João Pessoa, do aeroporto internacional Gilberto Freyre. Os procedimentos abordados pela ferramenta FlightInstructor, desenvolvida neste Trabalho de Graduação, são balizados por basicamente dois tipos de auxílio: Non-Directional Beacon (NDB) e VHF Omni-directional Radio Range (VOR). O símbolo dos auxílios VOR denominado REC e NDB OLD do SID João Pessoa são destacados na Figura 3. Figura 3. Auxílios VOR REC (esquerda) e NDB OLD (direita). A Figura 4 exibe a posição de alguns instrumentos no painel da aeronave Beechcraft Baron 58, disponível no FSX. Um auxílio VOR pode ser equipado com um Distance Measuring Equipment (DME), que associado a um instrumento de mesmo nome na aeronave (posição 1, na Figura 4), indica a sua distância em relação ao auxílio. O instrumento Course Deviation Indicator (CDI / posição 2) é associado ao auxílio VOR; o instrumento Automatic Direction 9 Finder (ADF / seta amarela, na posição 3), ao auxílio NDB. Cada auxílio emite ondas de rádio em uma determinada freqüência, que deve ser inserida na pilha de rádios da aeronave (posição 4). As freqüências do VOR REC (116,90 MHz) e do NDB OLD (380 KHz) estão selecionadas na Figura 4. A freqüência do VOR está inserida no campo NAV 1 da pilha de rádios, que representa o CDI principal. A aeronave ilustrada ainda possui um CDI secundário (seta verde na posição 3), representado pelo campo NAV 2. Figura 4. Posição de alguns instrumentos no painel da aeronave Beechcraft Baron 58. O Quadro 2 descreve algumas unidades de medida usadas na aviação. Essas unidades são exibidas nos procedimentos aeronáuticos, bem como no presente documento. Quadro 2. Unidades de medida usadas na aviação. Medida Distância horizontal Distância vertical Freqüência de um NDB Freqüência de um VOR Manifold pressure do motor Proa (sentido) Rotação do motor Velocidade horizontal Velocidade vertical Visibilidade Unidade Milha náutica (1 nm = 1852 metros) Pé (1' = 0,3048 metros) Quilohertz (KHz) Megahertz (MHz) Libra/polegada² (psi) Grau Rotação por minuto (rpm) Nó (kt) Pé/minuto (fps) Metro A proa da aeronave é indicada no instrumento heading indicator, que compartilha com o VOR o mesmo instrumento, chamado horizontal situation indicator, no painel da Figura 4. O ADF aponta para a posição do auxílio, em relação à aeronave. Na Figura 4, a aeronave está voando na proa 090 (Leste) e o NDB OLD está 50° à esquerda dessa proa. Os IAPs baseados em NDB, conhecidos como procedimentos de não precisão, ainda existem no Brasil, inclusive com única opção de IAP em alguns aeroportos, mas são menos comuns em outros países. Um IAP é baseado em um determinado auxílio quando esse auxílio é a principal referência disponível para o pouso. A Figura 5 ilustra o NDB ZBAA, localizado no aeroporto internacional Beijing Capital, na China. 10 Figura 5. NDB ZBAA (esquerda) e VOR PEK (direita), localizados no aeroporto Beijing Capital. O funcionamento de um auxílio VOR é mais complexo, porém é mais preciso e tem um alcance maior que um NDB. O auxílio VOR possui 360 radiais representadas pelo curso selecionado no instrumento CDI. A deflexão do CDI indica a posição da aeronave em relação à radial selecionada. Quando o CDI está centralizado, a aeronave se encontra na linha imaginária que representa a radial. Os IAPs baseados em um auxílio VOR são mais comuns, e também conhecidos como procedimentos de não precisão. A Figura 5 ilustra o VOR PEK, localizado no aeroporto Beijing Capital. IAPs baseados no Instrument Landing System (ILS) são considerados procedimentos de precisão. O ILS é um auxílio composto por dois subsistemas que conduzem a aeronave para o pouso durante a última etapa da aproximação: o localizer provê orientação horizontal; e o glideslope, vertical. A Figura 6 ilustra o localizer presente no ILS do aeroporto municipal Mena Intermountain, em Arkansas, nos Estados Unidos. O instrumento associado ao auxílio ILS é o mesmo usado pelo VOR, onde o CDI indica a posição da aeronave em relação ao localizer; e um outro recurso visual (desativado na Figura 4), em relação ao glideslope. Figura 6. Localizer presente no ILS do aeroporto Mena Intermountain. O intuito dessa seção não foi esgotar os assuntos relacionados ao vôo sob IFR, mas fornecer uma visão geral sobre os assuntos abordados no documento. Os detalhes sobre o vôo sob IFR, bem como as regras do tráfego aéreo brasileiro, podem ser encontrados no livro Regulamentos de Tráfego Aéreo – Vôo por Instrumento [4]. 2.3. Ferramentas Relacionadas Existem muitos produtos dedicados ao processo de ensino na aviação, que vão de livros a aplicações interativas para PC. Nesta seção, serão exibidos apenas alguns produtos considerados mais relevantes, de acordo com a sua categoria. 11 2.3.1. Livros O livro é uma das mídias mais acessíveis e usadas nas escolas de aviação, durante o processo de ensino. Microsoft Flight Simulator X For Pilots e Microsoft Flight Simulator as a Training Aid são as principais referências teóricas usadas no desenvolvimento do FlightInstructor [5][6]. Esses livros abordam de forma eficiente os recursos oferecidos pelo FSX, complementando a parte prática dos cursos de PPA e PCA. O primeiro, em especial, extrapola os limites do simulador nos assuntos abordados sendo uma referência muito importante para todo piloto que deseja explorar ao máximo os recursos oferecidos pelo FSX. 2.3.2. Cursos com Recursos Multimídia Os cursos de treinamento da Oxford Aviation Training (OAT) são exemplos de aplicações interativas com recursos multimídia para facilitar o ensino de diversos assuntos relacionados ao curso de PPA e PCA. O fato de oferecerem recursos multimídia e uma certa interatividade os torna mais dinâmicos que um livro, mas ainda assim seu conteúdo é limitado à parte teórica dos cursos. Uma interface do curso é ilustrada na Figura 7 [7]. Figura 7. Curso multimídia da OAT. 2.3.3. Simuladores de Sistemas Isolados Há ainda as aplicações que simulam o comportamento de certas interfaces de interação em uma aeronave, de maneira isolada. Pode-se citar como exemplo o G1000 PC Trainer, que simula o comportamento do sistema integrado de instrumentos de vôo Garmin G1000, ilustrado na Figura 8 [8]. O sistema equipa muitas aeronaves produzidas atualmente. Esse tipo de simulador não representa um curso em si, mas pode ser usado como tal por um instrutor. Sua limitação é simular apenas um dos sistemas da aeronave, possibilitando um treinamento muito específico. Algumas aeronaves oferecidas pelo FSX são equipadas com o Garmin G1000 com quase todas as suas funcionalidades, permitindo ao usuário simular o seu funcionamento junto 12 a outros sistemas da aeronave. O FSX oferece um capítulo específico em seu Learning Center, descrito a seguir, dedicado ao uso do G1000, mas já há livros que abordam o assunto de maneira mais aprofundada, como o Glass Simming: Garmin 1000, do autor Bill Stack, ainda em desenvolvimento. Figura 8. Garmin G1000 na cabine de um Cessna 172 Skyhawk. 2.3.4. Learning Center do FSX O próprio FSX oferece o Learning Center, ilustrado na Figura 9, que é uma seção destinada ao ensino dos conceitos básicos da aviação para diferentes etapas dos cursos de PPA e PCA. Além do material escrito e bem ilustrado para a parte teórica, possui checkrides (testes práticos) e missões, que analisam o comportamento do aluno em situações específicas. Ainda há a possibilidade de um instrutor se conectar remotamente ao PC do aluno e interagir com a aeronave como se estivessem juntos. Figura 9. Interface do Learning Center do FSX. 13 Nos checkrides, o instrutor virtual do Learning Center passa algumas instruções para o aluno e verifica se as executou corretamente, aprovando-o ou não para a próxima etapa do curso. Sua limitação é abordar apenas um único procedimento para cada etapa. Além disso, o SDK do FSX não oferece recursos para a modificação ou criação de novos checkrides. O conceito de missão foi apresentado no FSX, e representa um conjunto de objetivos que o piloto precisa cumprir para ter sucesso. O SDK inclusive permite a criação de novas missões, mas os recursos que oferece são limitados para uma análise mais precisa das ações executadas pelo piloto. O FSX ainda permite a criação de vídeos, que é um instrumento interessante de ensino quando se deseja apenas ilustrar a execução de uma tarefa. Esse recurso é oferecido como material complementar pelos livros [5] e [6]. 2.3.5. Instrutores de Vôo Virtuais O FSFlyingSchool representa o que há de mais próximo conceitualmente ao módulo FlightAnalyzer da ferramenta FlightInstructor [9]. O FSFlyingSchool simula um instrutor de vôo virtual para o FSX (bem como outras versões do simulador) que analisa e orienta o aluno, usando áudio e texto, em diversas etapas do vôo. Entre outros recursos, oferece um plano de carreira para o aluno, onde são analisados diversos aspectos da sua performance, destacando os pontos críticos e sugerindo melhorias. Uma interface da aplicação é ilustrada na Figura 10. Figura 10. Interface do FSFlyingSchool. 14 3. Microsoft Flight Simulator X A Microsoft lançou a primeira versão do seu simulador em 1982 [10]. Vinte e cinco anos depois, após várias versões e melhorias, foi lançada a versão X. Interfaces das versões 1 e X, respectivamente, são exibidas na Figura 11. Figura 11. Primeira versão do Flight Simulator (esquerda) e sua versão X (direita). O FSX está disponível nas versões Standard e Deluxe. A versão Deluxe oferece mais aeronaves, aeroportos e o SDK, que permite o desenvolvimento de aplicações para o simulador. O FSX é considerado um simulador de baixo custo, pois sua versão Standard pode ser adquirida por menos de R$ 100,00 na maioria das lojas de informática brasileiras. Segundo os autores dos livros [5] e [6], que são instrutores de vôo, o FSX simula com precisão diversos aspectos do vôo real, e é usado como ferramenta de ensino em várias escolas de aviação. Figura 12. Dispositivos de interação com o FSX. 15 O FSX pode ser utilizado com mouse e teclado, como dispositivos de entrada. Segundo os autores citados, é o suficiente para usá-lo de forma eficiente em muitos assuntos do curso. Porém, para aqueles que desejam aumentar a imersão na simulação, pode-se adquirir mais alguns dispositivos como yoke ou joystick, quadrante de manetes, pedais e tracker (rastreador) dos movimentos da cabeça do usuário. A Figura 12 ilustra os dispositivos de interação citados, além de outros disponíveis no mercado. A função do yoke ou joystick é controlar os movimentos de pitch e roll da aeronave. Como exemplo de yoke, pode-se citar o Flight Sim Yoke da CH Products, que ainda possui mais três eixos para o controle dos principais manetes de um monomotor, como o manete que controla a velocidade da aeronave [14]. Os pedais controlam o movimento de yaw da aeronave, além de freá-la em solo. Pode-se citar o Pro Pedals da CH Products como exemplo [14]. A função do tracker citado é controlar de forma intuitiva a visão do piloto dentro da cabine da aeronave, quando está exibindo o seu painel 3D. O TrackIR 4:Pro da NaturalPoint é um dos mais conhecidos no meio [15]. Figura 13. Cenário de Las Vegas produzido pela MegaScenery. Há uma grande comunidade de desenvolvedores dedicados ao FSX, produzindo cenários, aeronaves e aplicações, muitas vezes gratuitos. São dezenas de novos plug-ins sendo oferecidos todos os dias, em sites como o FlightSim.com, totalizando milhares de cenários e aeronaves disponíveis para o simulador [11]. Também existem empresas dedicadas ao desenvolvimento de plug-ins com qualidade superior aos recursos oferecidos pelo simulador, que podem custar o mesmo preço do FSX, dependendo da sua complexidade. Pode-se citar como exemplos a Carenado, que desenvolve aeronaves, e a MegaScenery, que produz cenários muito realistas, como o de Las Vegas, ilustrado na Figura 13 [12][13]. 16 3.1. SimConnect O SimConnect é um protocolo de comunicação oferecido pelo SDK do FSX, que permite o desenvolvimento de aplicações distribuídas para o simulador. O protocolo é baseado na arquitetura cliente/servidor e oferece acesso assíncrono a variáveis e eventos do FSX, que atua como o servidor [16]. As variáveis representam o estado da simulação e os eventos compreendem as ações que o usuário pode executar para modificar seu estado. Algumas variáveis só permitem a leitura do seu valor, como a que representa o interruptor que aciona os instrumentos de navegação em uma aeronave. Tal variável pode assumir os valores ligado e desligado. Para modificá-la, é necessário disparar um evento específico que alterna a posição do interruptor mencionado. Vale ressaltar que, para alguns componentes, há vários eventos relacionados, como é o caso do manete de potência, com mais de 50 eventos para manipulá-lo. Há centenas de variáveis e eventos disponíveis na Application Programming Interface (API), o que abre muitas possibilidades de interação com o simulador. É um campo aberto para o desenvolvimento de aplicações relacionadas à aviação. O padrão publisher/subscriber é usado como base da comunicação. O cliente solicita a leitura ou modificação do valor de uma variável ou envia um evento para o servidor, que faz o processamento de acordo com o nível de prioridade previamente estabelecido. A linguagem de programação padrão utilizada pela API do SimConnect é C++, mas oferece wrappers para código gerenciado, como C# e VB.NET. A linguagem escolhida para o desenvolvimento do FlightInstructor foi C# por conta das ferramentas oferecidas para a linguagem, que a torna mais produtiva que C++. O SDK do FSX só é oferecido pela versão Deluxe do simulador, mas as aplicações desenvolvidas podem ser executadas em sua versão Standard ou em clientes sem o simulador, quando a aplicação é distribuída. O SDK das versões anteriores do Flight Simulator não oferecia um protocolo de comunicação como o SimConnect. Os desenvolvedores de aplicações usavam freqüentemente uma biblioteca chamada FSUIPC, desenvolvida pelo Peter Dowson, que oferece acesso aos recursos do simulador mediante endereçamento de memória [17]. A escolha pelo uso do SimConnect se deve ao fato de ser um protocolo oferecido pela própria Microsoft, que oferece suporte aos desenvolvedores. Além disso, FSUIPC não suporta diretamente o desenvolvimento de aplicações usando a linguagem C#. Para os usuários da linguagem Java, ainda há a biblioteca jSimConnect, que é uma reimplementação em Java do protocolo SimConnect [18]. Possui uma excelente documentação e atualizações constantes. Permite que a aplicação cliente seja executada em qualquer plataforma suportada por uma máquina virtual Java. 17 4. FlightInstructor O FlightInstructor é um instrutor de vôo virtual para o FSX que complementa a etapa prática do curso de PCA, abordando alguns assuntos relacionados ao vôo sob IFR. Ele permitirá que o aluno pratique alguns conceitos aprendidos no curso, em especial durante o treinamento no simulador, sem a necessidade presencial de um instrutor de vôo. Vale a pena ressaltar que o FlightInstructor não substitui o instrutor real de vôo, atuando apenas como material complementar durante o aprendizado. O FlightInstructor é composto pelos módulos EasyConnect, ProcedurePerformer e FlightAnalyzer. O EasyConnect é uma camada de abstração para o SimConnect, que é o protocolo de comunicação com o FSX oferecido pelo seu SDK. O ProcedurePerformer é responsável pela execução de alguns procedimentos IFR como SID, STAR e IAP. Cada tarefa executada pelo instrutor virtual é exibida para o aluno na interface textual do módulo, como uma forma de orientá-lo na execução do procedimento. O FlightAnalyzer, por sua vez, será responsável pela análise de um determinado procedimento executado pelo aluno, e terá como finalidade apontar seus erros e sugerir correções. O processo de desenvolvimento dos módulos EasyConnect e ProcedurePerformer passa pelas seguintes etapas, descritas nas próximas seções: estudo dos conceitos relacionados ao domínio da aplicação, estudo do protocolo SimConnect e suas particularidades para C#, desenvolvimento do módulo EasyConnect e desenvolvimento do módulo ProcedurePerformer. A última seção descreve conceitualmente o módulo FlightAnalyzer, bem como sua relação com outros produtos relacionados ao FlightInstructor. 4.1. Domínio da Aplicação Os conceitos relacionados ao domínio da aplicação foram pesquisados sob demanda nos livros [5] e [6], de acordo com a etapa do desenvolvimento. Porém, é importante ter em mãos fontes complementares de pesquisa relacionadas aos conceitos do vôo por instrumento, a legislação do tráfego aéreo e os manuais de operação das aeronaves presentes na aplicação. 4.2. SimConnect para C# A documentação para o uso do SimConnect fornecida pelo SDK é abrangente, e traz vários exemplos de aplicações simples para ilustrar seus principais recursos. Porém, a compreensão do seu funcionamento não é trivial e a API está focada no uso da linguagem C++, com apenas três exemplos escritos em C#. O processo de desenvolvimento de uma aplicação para o FSX exige muitas linhas de código distribuídas em diversas estruturas da linguagem para a execução de tarefas relativamente simples. Tomando como referência os exemplos de aplicação oferecidos pelo SDK que são escritos em C#, uma aplicação com os requisitos mínimos necessários para o 18 gerenciamento da posição do manete de potência da aeronave poderia ter a seguinte configuração: ... using Microsoft.FlightSimulator.SimConnect; using System.Runtime.InteropServices; class ThrottleLever : Form { public const int SimConnectMessage = 0x0402; public enum DefineID { ThrottleLever } public enum EventID { OneSecond, Pause } public enum GroupID { } public enum RequestID { ThrottleLever } private ThrottleLeverStr throttleLever; [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)] public struct ThrottleLeverStr { public double value; } private SimConnect simConnect; public ThrottleLever() { ... try { simConnect = new SimConnect("SimConnect", Handle, SimConnectMessage, null, 0); simConnect.OnRecvOpen += new SimConnect.RecvOpenEventHandler( simConnect_OnRecvOpen); simConnect.OnRecvQuit += new SimConnect.RecvQuitEventHandler( simConnect_OnRecvQuit); simConnect.OnRecvException += new SimConnect.RecvExceptionEventHandler( simConnect_OnRecvException); simConnect.OnRecvEvent += new SimConnect.RecvEventEventHandler( simConnect_OnRecvEvent); simConnect.SubscribeToSystemEvent( Component.EventID.OneSecond, "1Sec"); simConnect.SubscribeToSystemEvent(Component.EventID.Pause, "Pause"); } catch (COMException e) { } } 19 public double GetThrottleLever() { return throttleLever.value; } public void SetThrottleLever(double value) { throttleLever.value = value; simConnect.SetDataOnSimObject(DefineID.ThrottleLever, SimConnect.SIMCONNECT_OBJECT_ID_USER, 0, throttleLever); } public void OneSecond() { } public void Pause(bool isPaused) { } private void simConnect_OnRecvOpen(SimConnect sender, SIMCONNECT_RECV_OPEN data) { simConnect.AddToDataDefinition(DefineID.ThrottleLever, "GENERAL ENG THROTTLE LEVER POSITION:1", "Percent", SIMCONNECT_DATATYPE.FLOAT64, 0.1f, SimConnect.SIMCONNECT_UNUSED); simConnect.RegisterDataDefineStruct<ThrottleLeverStr>( DefineID.ThrottleLever); simConnect.RequestDataOnSimObject(RequestID.ThrottleLever, DefineID.ThrottleLever, SimConnect.SIMCONNECT_OBJECT_ID_USER, SIMCONNECT_PERIOD.VISUAL_FRAME, SIMCONNECT_DATA_REQUEST_FLAG.CHANGED, 0, 0, 0); simConnect.OnRecvSimobjectData += new SimConnect.RecvSimobjectDataEventHandler( simConnect_OnRecvSimobjectData); } private void simConnect_OnRecvQuit(SimConnect sender, SIMCONNECT_RECV data) { } private void simConnect_OnRecvException(SimConnect sender, SIMCONNECT_RECV_EXCEPTION data) { } private void simConnect_OnRecvEvent(SimConnect sender, SIMCONNECT_RECV_EVENT data) { switch (data.uEventID) { case (uint)Component.EventID.OneSecond: OneSecond(); break; case (uint)Component.EventID.Pause: bool isPaused = false; if (data.dwData == 1) { isPaused = true; } Pause(isPaused); break; } } private void simConnect_OnRecvSimobjectData(SimConnect sender, SIMCONNECT_RECV_SIMOBJECT_DATA data) { switch ((RequestID)data.dwRequestID) { case RequestID.ThrottleLever: throttleLever = (ThrottleLeverStr)data.dwData[0]; break; 20 } } protected override void DefWndProc(ref Message m) {...} } Todos os exemplos oferecidos para C# usam classes que herdam do tipo System.Windows.Forms.Form, por causa do seu atributo Handle, usado na inicialização do SimConnect indicado em simConnect = new SimConnect(...). Handle é responsável pela chamada ao método void DefWndProc(...), que captura para a aplicação as mensagens relativas ao SimConnect, emitidas pelo FSX. Cada variável a ser gerenciada pela aplicação precisa ter um identificador que a represente nos enums DefineID e RequestID, e ter o valor do seu estado armazenado em um exemplificado struct, pelo ThrottleLeverStr na aplicação. EventID guarda os identificadores dos eventos presentes na aplicação. GroupID, que está vazio no exemplo, agrupa os eventos de acordo com a prioridade com a qual devem ser tratados pelo FSX. O atributo value de ThrottleLeverStr representa a posição do manete de potência na simulação. Cada struct pode armazenar mais de uma variável, em atributos diferentes. A inicialização da variável é feita no método void simConnect_OnRecvOpen(...), que é chamado logo após a conexão com o servidor. Durante a inicialização, em simConnect.AddToDataDefinition(...), o string "GENERAL ENG THROTTLE LEVER POSITION:1", que pode ser encontrado na documentação do SDK, indica ao servidor que a variável manete de potência deve ser associada ao DefineID.ThrottleLever. O valor 0.1f indica a variação mínima da posição do manete a ser considerada pelo servidor. Em os simConnect.RequestDataOnSimObject(...), ...PERIOD.VISUAL_FRAME ThrottleLeverStr será e ...PERIOD.CHANGED atualizado na são usados chamada ao argumentos para indicar método que void simConnect_OnRecvSimobjectData(...) a cada frame visual exibido pelo FSX, mas apenas quando o estado da variável for modificado na simulação. Entre outras, a API ainda oferece as opções de atualização ...PERIOD.SECOND, onde os structs são atualizados a cada segundo; e ...PERIOD.SIM_FRAME, a cada frame da simulação, para variáveis muito críticas. Os métodos responsáveis pela leitura e modificação da posição do manete são respectivamente double GetThrottleLever() e void SetThrottleLever(...). Para possibilitar essa abordagem em um protocolo assíncrono de comunicação foi necessário mudar a estrutura sugerida pelas aplicações de exemplo. O método que modifica a posição do manete apenas atualiza o atributo value de ThrottleLeverStr e chama o método simConnect.SetDataOnSimObject(...) passando uma referência ao struct como um dos argumentos. O método que lê a posição do manete, por outro lado, apenas retorna o valor 21 do atributo value de ThrottleLeverStr, que é atualizado de acordo com as opções selecionadas durante a inicialização do componente. Durante o processo de estudo do SimConnect, foram consultados alguns fóruns dedicados ao assunto na Internet, como os da AVSIM e FsDeveloper [19][20]. Eles possuem uma comunidade ativa de desenvolvedores e são fontes de pesquisa fundamentais para a compreensão de alguns detalhes específicos e limitações da API. Dentre os exemplos de aplicação escritos em C++ oferecidos pelo SDK, vários foram traduzidos pela comunidade para C#. Essa tradução é muito importante para os desenvolvedores iniciantes, que optaram pelo código gerenciado, já que a utilização de alguns recursos oferecidos pelo SDK não é ilustrada pelos seus poucos exemplos disponíveis em C#. Além disso, algumas inconsistências existentes entre as APIs para C++ e C# foram resolvidas pelos tradutores desses exemplos, com algumas soluções alternativas. O Service Pack 1 (SP1) do SDK do FSX corrigiu alguns problemas e adicionou novos recursos. Porém, ainda há alguns problemas como a existência de variáveis e eventos que estão disponíveis na API, mas não foram devidamente implementados. Após o lançamento do SP2 do FSX, foi disponibilizado o SP2 do SDK, que basicamente o torna compatível com a nova atualização do simulador. 4.3. Módulo EasyConnect O módulo EasyConnect representa uma camada de abstração entre uma aplicação a ser desenvolvida para o FSX e a API para C# oferecida pelo SimConnect. Seu objetivo é separar a lógica da aplicação das particularidades do SimConnect, tornando seu código legível e gerenciável. O desenvolvimento de um módulo como o EasyConnect teve como motivação a demanda existente em fóruns como [19] e [20] por uma ferramenta que simplificasse o uso do SimConnect. Tomando como exemplo a aplicação exibida na seção anterior, é possível perceber que a monitoração de mais variáveis da simulação aumentaria substancialmente o seu código, dificultando a sua compreensão e manutenção. No contexto do FlightInstructor, o EasyConnect representa o módulo de comunicação entre os módulos ProcedurePerformer e FlightAnalyzer, e o FSX. A abstração fornecida pelo EasyConnect consiste em representar as variáveis da simulação como uma coleção de componentes, com métodos para ler e modificar seus valores. A aeronave que está sendo controlada pelo usuário do FSX, por exemplo, é interpretada como uma coleção de componentes específicos que representam os seus pontos de interação, como botões, interruptores, mostradores, manetes, etc. Em seu estágio atual de desenvolvimento, o EasyConnect prioriza as necessidades do módulo ProcedurePerformer, fornecendo os componentes necessários para a execução dos procedimentos abordados. O Quadro 3 descreve alguns componentes oferecidos pelo EasyConnect, que serão referenciados no documento. A descrição tem como finalidade esclarecer de maneira superficial a função de cada componente presente na aeronave. A Figura 14 ilustra o painel do Beechcraft Baron 58 e indica a posição dos componentes citados. 22 Quadro 3. Descrição de alguns componentes oferecidos pelo EasyConnect. Componente APAltitudeKnob (posição 1 na Figura 14) APAltitudeSwitch (1) APApproachSwitch (1) APHeadingKnob (2) APHeadingSwitch (1) APMasterSwitch (1) APNAV1Switch (1) APVerticalSpeedKnob (1) EngManifoldPressure (3) EngRPM (4) FlapsHandle (5) GearHandle (6) HeadingIndicator (2) IndicatedAltitude (8) IndicatedAirspeed (9) NAV1CDI (2) NAV1Frequency (10) NAV1Knob (2) NAVDME (11) PropellerLever (12) ThrottleLever (13) Descrição Altitude mantida pelo piloto automático da aeronave (PA). Aceita valores inteiros, positivos e múltiplos de 100' Acionamento do modo de controle de altitude pelo PA. Aceita os valores ligado (true) e desligado (false) Acionamento do modo de controle de proa e altitude para o localizer e glideslope de um ILS pelo PA. Aceita os valores ligado (true) e desligado (false) Proa mantida pelo PA. Aceita valores positivos e múltiplos de 1 Modo de controle de proa pelo PA. Aceita os valores ligado (true) e desligado (false) Acionamento geral do PA. Aceita os valores ligado (true) e desligado (false) Acionamento do modo de controle de proa para a radial do VOR indicado no CDI principal pelo PA. Aceita os valores ligado (true) e desligado (false) Velocidade vertical mantida pelo PA. Aceita valores positivos e múltiplos de 100' Manifold pressure dos motores. Assume valores positivos e múltiplos de 0,1 psi Rotação dos motores. Assume valores positivos e múltiplos de 5 rpm Posição dos flaps. Aceita valores positivos e múltiplos de 1 Posição do trem de pouso. Aceita os valores estendido (true) e retraído (false) Proa da aeronave. Assume valores positivos, múltiplos de 0,1, entre 0 e 360° Altitude indicada da aeronave. Assume valores positivos e múltiplos de 0,1' Velocidade indicada da aeronave. Assume valores positivos e múltiplos de 0,1 kt Deflexão do CDI principal. Assume valores entre –1 e 1 Freqüência selecionada no NAV 1 da pilha de rádios. Aceita valores positivos e múltiplos de 0,01 MHz Curso selecionado no CDI principal. Aceita valores positivos, múltiplos de 1, entre 0 e 360° Distância indicada no DME. Assume valores positivos e múltiplos de 0,1 nm Manete de passo de hélice. Aceita valores positivos entre 0 e 100% Manete de potência. Aceita valores positivos entre 0 e 100% 23 Figura 14. Localização de alguns componentes no painel da aeronave Beechcraft Baron 58. 4.3.1. Arquitetura Os componentes oferecidos pelo EasyConnect precisam ser carregados pela aplicação, antes da sua utilização, para que sejam inicializados corretamente. Essa necessidade de carregamento tem como finalidade poupar a comunicação com o servidor, evitando que componentes não utilizados pela aplicação gerem tráfego de informação e processamento desnecessários para o FSX. Cada componente possui um método para carregamento e é representado por um atributo específico na classe EasyConnect. O componente manete de potência, por exemplo, é representado pelo atributo propellerLever e carregado pelo método void LoadThrottleLever(). A arquitetura simplificada do EasyConnect é ilustrada na Figura 15. Figura 15. Arquitetura do módulo EasyConnect. Os componentes são armazenados em classes que herdam da classe Component, que guarda os enums DefineID, EventID, GroupID e RequestID, equivalentes aos enums 24 de mesmo nome na classe da seção anterior. Cada componente segue o padrão da classe a seguir, que representa o manete de potência: public class ThrottleLever : Component { public VariableStr str; [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)] public struct VariableStr { public double value; } public ThrottleLever(SimConnect simConnect) : base(simConnect) { simConnect.AddToDataDefinition(DefineID.ThrottleLever, "GENERAL ENG THROTTLE LEVER POSITION:1", "Percent", SIMCONNECT_DATATYPE.FLOAT64, 0.1f, SimConnect.SIMCONNECT_UNUSED); simConnect.RegisterDataDefineStruct<VariableStr>( DefineID.ThrottleLever); simConnect.RequestDataOnSimObject(RequestID.ThrottleLever, DefineID.ThrottleLever, SimConnect.SIMCONNECT_OBJECT_ID_USER, SIMCONNECT_PERIOD.VISUAL_FRAME, SIMCONNECT_DATA_REQUEST_FLAG.CHANGED, 0, 0, 0); simConnect.OnRecvSimobjectData += new SimConnect.RecvSimobjectDataEventHandler( simConnect_OnRecvSimobjectData); } public double GetVar() { return str.value; } public void SetVar(double value) { str.value = value; simConnect.SetDataOnSimObject(DefineID.ThrottleLever, SimConnect.SIMCONNECT_OBJECT_ID_USER, 0, str); } private void simConnect_OnRecvSimobjectData(SimConnect sender, SIMCONNECT_RECV_SIMOBJECT_DATA data) { if ((RequestID)data.dwRequestID == RequestID.ThrottleLever) { str = (VariableStr)data.dwData[0]; } } } Cada componente tem seu estado armazenado em um struct, permitindo que possam ser carregados individualmente. O struct VariableStr {...} guarda a posição do manete de potência em um double. É equivalente ao struct ThrottleLeverStr {...} na classe da seção anterior. Algumas variáveis do SimConnect só permitem a leitura do seu estado, como a que é representada pelo componente APMasterSwitch, de EasyConnect. É necessário disparar um evento relacionado à variável para modificar seu estado, como o AP_MASTER, que alterna o 25 seu valor. O componente APMasterSwitch oferece o método void KeyToggle(), que dispara o evento mencionado. Há alguns componentes semelhantes, como o NAV1Frequency, cujo evento disponível exige que o valor de entrada seja formatado como um binary-coded decimal. O componente oferece o método void KeySet(double value), que faz as conversões necessárias e dispara o evento. O construtor da classe é responsável pela inicialização do componente. As opções de atualização em simConnect.RequestDataOnSimObject(...) foram selecionadas previamente de acordo com a natureza do componente em questão. Para o componente que exibe a velocidade da aeronave, por exemplo, foi escolhida a opção ...PERIOD.SECOND, já que o componente sofre variações durante praticamente toda a simulação. Essa opção também tem a finalidade de poupar a comunicação com o servidor, evitando a queda de performance da simulação. Por outro lado, o componente manete de potência só precisa ser ajustado em alguns momentos específicos durante o vôo, permitindo ser atualizado pela opção ...PERIOD.VISUAL_FRAME. O SimConnect oferece variáveis que informam a presença ou configuração de alguns dispositivos relevantes na aeronave. O estado dessas variáveis é agrupado no componente Capabilities, e tem o seu valor atualizado apenas uma vez, durante o seu carregamento. O EasyConnect ainda oferece um componente que permite a impressão de um string sem formatação na interface textual do simulador (Text), além de algumas constantes que facilitam a conversão das unidades de medida usadas pelo SimConnect. A aplicação que utiliza o EasyConnect precisa implementar a interface EasyListener, exibida a seguir, e se registrar como listener chamando o método void AddListener(EasyListener listener) da classe EasyConnect, para ser notificado de alguns eventos de sistema lançados pelo FSX. public interface EasyListener { void Open(); void Quit(); void Exception(string exception); void OneSecond(); void Pause(bool isPaused); } O método void Open() de cada listener é chamado quando a conexão com o FSX é aberta com sucesso; void Quit(), quando a conexão com o servidor é fechada; void Exception(string exception), quando alguma exceção é lançada pelo FSX, passando o seu código como parâmetro, que pode ser consultado na documentação do SDK; void OneSecond(), a cada segundo de simulação, que pode ser usado como temporizador da 26 aplicação; e void Pause(bool isPaused), quando o evento que alterna o estado da simulação entre os valores paused e unpaused é lançado pelo servidor. 4.3.2. Aplicação de Exemplo Tomando como referência as funcionalidades da aplicação exibida na seção anterior, a versão equivalente em uma aplicação que utiliza o EasyConnect poderia ter a seguinte configuração: ... using EasyConnect; class ThrottleLever : Form, EasyListener { private EasyConnect ec; public ThrottleLever() { ... ec = new EasyConnect(); ec.Connect(this); ec.AddListener(this); } public double GetThrottleLever() { return ec.throttleLever.GetVar(); } public void SetThrottleLever(double value) { ec.throttleLever.SetVar(value); } public void Open() { ec.LoadThrottleLever(); } public void Quit() { } public void Exception(string exception) { } public void OneSecond() { } public void Pause(bool isPaused) { } protected override void DefWndProc(ref Message m) {...} } Essa aplicação tem o código mais legível e gerenciável, pois não precisa lidar com as particularidades da API oferecida pelo SimConnect. Dessa forma, os usuários do EasyConnect podem desenvolver mais facilmente uma aplicação para o FSX, mesmo que não conheçam os detalhes da API. 27 4.4. Módulo ProcedurePerformer O módulo ProcedurePerformer (PP) é responsável pela execução de procedimentos aeronáuticos, atuando como um instrutor de vôo virtual na etapa de instrução onde é ensinada a maneira correta de se executar o procedimento, usando a aeronave escolhida. Cada tarefa executada pelo instrutor é exibida para o aluno pela interface gráfica do PP, que é integrada à interface textual do FSX. Durante a execução do procedimento, o aluno não interage com a aplicação. A motivação para o desenvolvimento do presente módulo vem da dificuldade encontrada pelos alunos em executar de maneira correta as etapas de um procedimento. O procedimento é representado como uma máquina de estados, onde cada estado representa um determinado trecho do procedimento. No fim de alguns trechos, o procedimento pode tomar rumos diferentes, dependendo do estado atual da simulação. A divisão do procedimento em trechos é feita estrategicamente nos pontos onde o piloto precisa executar um conjunto de tarefas. Durante o vôo, o aluno carrega o PP e escolhe o procedimento a ser executado dentre os disponíveis. Cada procedimento é armazenado em um arquivo de configuração, que contém todas as informações relevantes para sua execução. PP detecta a aeronave em uso e a procura em seu banco de aeronaves. Cada aeronave também é armazenada em um arquivo de configuração, que contém seus padrões operacionais. Os arquivos de procedimentos e aeronaves são carregados e interpretados pelos parsers apropriados de PP. A adição de arquivos de configuração torna a aplicação expansível para novos procedimentos e aeronaves. 4.4.1. Arquitetura PP usa o módulo EasyConnect para se comunicar com o FSX, evitando as particularidades do SimConnect. A arquitetura simplificada do PP é ilustrada na Figura 16. Figura 16. Arquitetura do módulo ProcedurePerformer. 28 Um procedimento (Procedure) possui alguns identificadores e uma hash table que armazena os seus estados (Dictionary<string, State> states), tendo como chave o nome do estado. Cada estado (State) tem uma lista de tarefas (List<Task> tasks) associadas e uma lista de condições de mudança de estado (List<Change> changes). Uma tarefa (Task) corresponde a uma ação do piloto durante a execução do procedimento, e possui um nome (string name) e um valor (string value). A condição de mudança (Change) basicamente é composta por uma lista de condições individuais (List<Condition> conditons) e o próximo estado (string nextState) a ser carregado caso todas as condições individuais sejam satisfeitas. A condição individual (Condition) possui um nome (string name), que geralmente representa um componente da aeronave, a relação (string relation), e um valor (string value). A classe ProcedurePerformer tem uma fila de tarefas (Queue<Task> tasks) que é alimentada por cada estado alcançado, pois pode haver mudança de estado sem que todas as suas tarefas tenham sido executadas. Além disso, há o conceito de tarefas concorrentes (Task concTask), que são executadas paralelamente a outras tarefas até a sua conclusão ou mudança de estado. Algumas tarefas são simples e só precisam de um ciclo da aplicação para ser executadas, como mudar a posição de um interruptor na aeronave. Por outro lado, algumas precisam de mais de um ciclo, pois envolvem mais de um componente para sua conclusão, como é o caso de se modificar a posição do manete de potência da aeronave para que ela atinja uma determinada velocidade. Enquanto pequenos incrementos são feitos na posição do manete, é verificada a velocidade atual no componente velocímetro. PP possui métodos auxiliares para o tratamento dessas tarefas complexas. A execução de uma tarefa também depende do tipo de aeronave utilizada e seus componentes disponíveis. Vale ressaltar que o SimConnect permite a execução de tarefas complexas, como a citada acima, de maneira direta, com apenas a chamada de um método. Porém, PP tem a intenção de simular um instrutor de vôo de maneira realista, passando pelos passos descritos. 4.4.2. Ciclo da Aplicação O ciclo da aplicação ocorre a cada segundo da simulação. Como o PP utiliza o EasyConnect em sua comunicação com o FSX, precisa implementar a interface EasyListener. Conseqüentemente, além de outros eventos de sistema, é notificado a cada segundo de simulação através da chamada ao seu método void OneSecond(), exibido a seguir, que representa um temporizador. public void OneSecond() { PrintStatus(); if (!isPaused) { if (taskInterval == 0) { if (tasks.Count > 0) { PerformTask(tasks.Peek()); if (!isPerformingTask) { tasks.Dequeue(); 29 taskInterval = 4; ... } } } else { taskInterval--; } if (concTask != null) { PerformTask(concTask); if (!isPerformingTask) { concTask = null; } } foreach (Change change in currentState.changes) { CheckChange(change); } if (timer > 0) { timer--; } } } O método void PrintStatus() é responsável pela impressão do status da execução do procedimento na interface gráfica textual do PP, ilustrado na Figura 17. Na primeira linha (Tasks) são exibidas as últimas tarefas executadas, incluindo a atual. Na segunda linha, são exibidas a tarefa concorrente (Concurrent task) que está sendo executada (se houver) e o valor atual do cronômetro (Timer) simulado pelo PP. A terceira linha (Change) exibe as condições de mudança de estado, com suas condições individuais. Figura 17. Interface gráfica textual do módulo ProcedurePerformer. Se a simulação não estiver interrompida, o método void PerformTask(Task task), exibido a seguir, executa a primeira tarefa da fila. O método é composto por um longo switch que recebe o nome da tarefa (task.name) como parâmetro. public void PerformTask(Task task) { isPerformingTask = true; switch (task.name) { ... case "EngManifoldPressure": SetEngManifoldPressure(Double.Parse(task.value)); break; case "EngRPM": switch (task.value) { case "Max": SetPropellerLever(100); break; default: SetEngRPM(Int32.Parse(task.value)); break; 30 } break; ... case "GearHandle": ec.gearHandle.SetVar(Boolean.Parse(task.value)); isPerformingTask = false; break; ... case "Profile": foreach (Task profTask in profiles[task.value].tasks) { EnqueueTask(profTask); } isPerformingTask = false; break; ... } } A tarefa com o nome GearHandle, que manipula a posição do trem de pouso da aeronave, é executada em apenas um laço com a chamada ao método ec.gearHandle.SetVar(task.value), da classe EasyConnect, tendo como parâmetro o valor da tarefa. A tarefa EngManifoldPressure, que controla o parâmetro manifold pressure do motor da aeronave, é considerada uma tarefa complexa, sendo executada em mais de um ciclo, por um método auxiliar. O método SetEngManifoldPressure(...) recebe o valor da tarefa e faz pequenos ajustes no componente manete de potência (ec.throttleLever), até que o componente manifold pressure (ec.engManifoldPressure) atinja o valor desejado. EngRPM ilustra uma tarefa que pode ter valores de tipos diferentes. Ela controla a rotação do motor da aeronave (ec.engRPM) manipulando o manete de passo de hélice (ec.propellerLever), nas aeronaves que possuem esse componente. Se o valor da tarefa for Max, o método void SetPropellerLever(double value) é chamado, tendo como parâmetro 100%. Caso contrário, void SetEngRPM(int value) é chamado com o parâmetro numérico task.value. Caso a aeronave não possua o manete de passo de hélice (ec.propellerLever == null), o método manipula o manete de potência para atingir o objetivo. Finalmente, Profile ilustra uma tarefa que se desdobra em outras tarefas. O conceito de profile será explicado na próxima subseção, mas ele pode ser interpretado, no contexto do PP, como uma lista de tarefas que são adicionadas à fila da classe ProcedurePerformer, durante a execução da tarefa Profile. Voltando à execução do método void OneSecond(), após a chamada PerformTask(tasks.Peek()), se a tarefa atual foi finalizada, será removida da fila de tarefas. Em seguida, PerformTask(concTask) é chamado para executar a tarefa concorrente, se houver no momento. O laço a seguir verifica se a situação atual da simulação representa uma mudança de estado, percorrendo todas as condições de mudança do estado atual. O método CheckChange(change), exibido a seguir, verifica se alguma condição individual é atendida. 31 O método também é composto por um longo switch que recebe o nome da condição individual (condition.name) como parâmetro. public void CheckChange(Change change) { bool isChange = true; foreach (Condition condition in change.conditons) { switch (condition.name) { case "APMasterSwitch": isChange &= ec.apMasterSwitch.GetVar() == Boolean.Parse(condition.value); break; ... case "IndicatedAltitude": isChange &= IsCondition(ec.indicatedAltitude.GetVar(), condition, 10); break; ... } } if (isChange) { currentState = procedure.states[change.nextState]; EnqueueStateTasks(); } } A condição individual com o nome APMasterSwitch se refere ao componente interruptor que controla o acionamento do piloto automático da aeronave (ec.apMasterSwitch). O valor da condição (condition.value) é comparado ao valor do estado atual do componente. A condição com o nome IndicatedAltitude se refere ao componente altímetro (ec.indicatedAltitude). O valor da condição é comparado ao valor do componente através do método bool IsCondition(...), que basicamente verifica se a relação da condição (condition.relation) é satisfeita. A comparação ainda leva em conta uma margem de erro, que no caso do componente em questão, foi estabelecido como 10 pés. Caso todas as condições individuais sejam satisfeitas, o próximo estado da condição de mudança (change.nextState) passa a ser o estado atual do procedimento, e as tarefas desse novo estado são adicionadas à fila da classe ProcedurePerformer. O SimConnect não oferece acesso ao cronômetro presente no relógio de algumas aeronaves do FSX. Como muitos procedimentos precisam de um temporizador, a classe ProcedurePerformer implementa um cronômetro simples (int timer), que conta o tempo em segundos, e é decrementado na última atividade do método void OneSecond(), finalizando um ciclo da aplicação. 4.4.3. Arquivos de Configuração O arquivo de configuração da aeronave escolhida, que armazena seus padrões operacionais, é carregado no método void LoadAircraft(). Esse método ainda carrega todos os componentes necessários para a execução dos procedimentos abordados pelo PP, de acordo com a disponibilidade informada pelo componente Capabilities, de 32 EasyConnect. A aeronave precisa ter um conjunto mínimo de dispositivos para poder ser usada na aplicação. Além dos instrumentos de navegação requeridos pelo procedimento, precisa ser equipada com um piloto automático com controle de proa (sentido) e altitude da aeronave. Desenvolver um algoritmo para o controle do seu manche e pedais, com essa finalidade, seria muito complexo e desnecessário, já que esse tipo de conhecimento já é dominado pelo aluno do curso de PCA. O arquivo de configuração da aeronave Mooney Bravo, oferecida pelo FSX, é exibido a seguir: ... Profile LowCruise Task EngManifoldPressure 25 Task EngRPM 2200 Task FlapsHandle 0 Task GearHandle False ... Profile ApproachDescent Task APVerticalSpeedKnob -500 Task EngManifoldPressure 19 Task EngRPM Max Task FlapsHandle 1 Task GearHandle True Profile ShortFinal Task APVerticalSpeedKnob -500 Task EngRPM Max Task FlapsHandle 2 Task GearHandle True Task IndicatedAirspeed 80 Os padrões operacionais da aeronave são representados como perfis de vôo. Segundo a metodologia sugerida pelos livros [5] e [6], toda aeronave tem uma configuração específica para cada etapa do vôo, que são chamados perfis de vôo. No arquivo de configuração, o perfil (Profile) é representado como um conjunto de tarefas, que configuram a aeronave de acordo com a etapa do vôo, como um checklist restrito a apenas alguns componentes da aeronave. O atributo Dictionary<string, Profile> profiles da classe ProcedurePerformer é uma hash table de perfis (Profile), tendo como chave o nome do perfil. A classe Profile, por sua vez, encapsula uma lista de tarefas (List<Task> tasks). O parser é composto por um switch, que recebe como argumento a primeira palavra de cada linha do arquivo de configuração. Para cada linha iniciada com a palavra Profile (como a linha Profile ApproachDescent), o parser instancia um perfil e o armazena na hash table da classe ProcedurePerformer de acordo com o seu nome (ApproachDescent). As linhas seguintes, iniciadas com Task (como a linha Task EngManifoldPressure 19), são interpretadas como tarefas, que têm como nome o primeiro argumento (EngManifoldPressure), e como valor o segundo (19). As tarefas são instanciadas e adicionadas na lista do último perfil criado. O arquivo de configuração do procedimento escolhido é carregado logo em seguida, no método void LoadProcedure(string procName). Esse arquivo armazena o identificador 33 do procedimento e todos os seus estados, com as respectivas tarefas e condições de mudança. O IAP ILX Y do aeroporto internacional Gilberto Freyre, em Recife, é representado pelo seguinte arquivo: ICAO SBRF Name ILX Y State Start Task APAltitudeKnob 3000 Task APAltitudeSwitch True Task APMasterSwitch True Task APHeadingKnob Heading Task APHeadingSwitch True Task NAV1Frequency 116.90 Task NAV1Knob Station Task APHeadingKnob Radial Task APNAV1Switch True Task Profile LowCruise Change Y2 Condition TaskQueueSize = 0 Condition NAVDME < 1 State Y2 Task APHeadingKnob Heading Task APHeadingSwitch True Task APHeadingKnob -018 Task NAV1Knob 018 Task APHeadingKnob Radial Task APNAV1Switch True Change Y3 Condition NAVDME > 10 State Y3 Task APAltitudeKnob 2000 Task NAV1Frequency 110.30 Task NAV1Knob 184 Task APHeadingKnob Heading Task APHeadingSwitch True Task APHeadingKnob -184 Task APHeadingKnob Radial Task APApproachSwitch True Task Profile ApproachDescent Change Y4 Condition TaskQueueSize = 0 Condition NAVDME < 5 State Y4 Task Profile ShortFinal Change End Condition NAVDME < 3 State End Task APMasterSwitch False O parser desse tipo de arquivo tem um funcionamento semelhante ao parser de aeronaves. As linhas que iniciam com as palavras ICAO e Name representam respectivamente o código da localidade e o nome do procedimento, que o identificam unicamente. O parser 34 instancia um procedimento e configura seus identificadores. Cada linha iniciada com State, como State Start, representa um estado do procedimento, que é instanciado e adicionado à hash table de estados da classe ProcedurePerformer de acordo com o seu nome (Start). Durante a execução do procedimento, o estado com o nome Start é considerado o seu estado inicial. As linhas seguintes, iniciadas com Task, são interpretadas como no parser de aeronaves, mas são adicionadas à lista de tarefas da classe State. A linha iniciada com Change (como a linha Change CruiseDescent) representa uma condição de mudança para o estado seguinte (CruiseDescent), que é instanciada e adicionada à fila do último estado criado. A linha seguinte (Condition IndicatedAltitude > 3500) inicia a lista de condições individuais, que relacionam (>) o nome da condição (IndicatedAltitude) com um valor (3500). As condições individuais são instanciadas a adicionadas à fila da última condição de mudança criada. 4.5. FlightAnalyzer O FlightAnalyzer é o módulo do FlightInstructor que será responsável pelo monitoramento do desempenho do aluno durante várias etapas do vôo. O instrutor virtual fará uma análise do desempenho do aluno, além de sugerir correções para os seus erros, como faria um instrutor de vôo real durante o processo de ensino. O módulo não será restrito aos procedimentos que exigem o uso do PA da aeronave, e poderá ser usado em outras etapas do vôo. O FlightAnalyzer usará como base os módulos do FlightInstructor EasyConnect e ProcedurePerformer, já desenvolvidos. Porém, o seu desenvolvimento demanda um estudo mais aprofundado do processo de ensino na aviação, o que não seria possível executar em tempo hábil durante o presente Trabalho de Graduação. 35 5. Estudo de Caso Para explicar a execução de um procedimento pelo módulo PP, tome-se como exemplo o IAP ILS Y, para pouso no aeroporto internacional Gilberto Freyre, em Recife. O procedimento é representado pela Instrument Approach Chart (IAC) ILS Y, que está ilustrada na Figura 18. Entre outras informações, a carta exibe uma vista superior e lateral do procedimento, as instruções para arremeter (cancelar o pouso) e os mínimos meteorológicos exigidos para o pouso. Figura 18. IAC ILS Y, para pouso no aeroporto Gilberto Freyre. Seu ponto de entrada é o auxílio VOR REC. Imaginemos que a aeronave usada seja um Mooney Bravo, que esteja a 5000' de altitude, na proa 010, ao Sul do aeroporto e distante do litoral. Imaginemos ainda que o aluno não saiba exatamente a sua posição, não esteja usando o PA e que as condições meteorológicas permitam a execução do IAP ILS Y. O procedimento será executado conforme os arquivos de configuração exibidos no capítulo 36 anterior. A Figura 19 ilustra o painel do Mooney Bravo e indica a posição dos componentes do EasyConnect citados no Quadro 3. Figura 19. Localização dos componentes citados no Quadro 3 no painel do Mooney Bravo. Após o seu carregamento, o PP detecta a aeronave Mooney Bravo e carrega seu arquivo de configuração do seu banco. Após a seleção do procedimento, ele é carregado do arquivo e as tarefas do seu primeiro estado (Start) são executadas. A Figura 20 ilustra a interface gráfica textual do PP durante a execução da primeira tarefa. A primeira linha da interface (Tasks) exibe as últimas tarefas executadas, incluindo a atual. A segunda linha exibe a tarefa concorrente (Concurrent task) que está sendo executada (se houver) e o valor atual do cronômetro (Timer) simulado pelo PP. A terceira linha (Change) exibe as condições de mudança de estado, com suas condições individuais. Figura 20. Execução do IAP ILS Y. No estágio atual da execução, o valor do componente APAltitudeKnob será modificado para 3000', não há tarefas concorrentes e o cronômetro não está sendo usado. Quando todas as tarefas do estado tiverem sido executadas e o valor do componente NAVDME for menor que 1 nm haverá mudança de estado. Não interessa ao aluno saber os nomes atribuídos aos estados do procedimento, mas quando terá um conjunto de novas tarefas para executar. A Figura 21 exibe a interface durante a execução da segunda tarefa. 37 Figura 21. Execução do IAP ILS Y. O espaço de tempo entre a execução de duas tarefas pode ser configurado pelo aluno, mas está definido atualmente em quatro segundos. A segunda tarefa consiste em modificar o valor de APAltitudeSwitch para ligado (true). Quatro segundos depois de ser exibida na interface, a tarefa será executada, o que se reflete na interface do FSX. Como as condições de mudança ainda não foram satisfeitas, o procedimento continua no mesmo estado. As tarefas seguintes são: mudar o valor de APMasterSwitch para ligado; APHeadingKnob para a proa atual da aeronave; APHeadingSwitch para ligado; NAV1Frequency para 116,90 MHz, do VOR REC; NAV1Knob para a radial mais próxima do VOR; APHeadingKnob para o curso selecionado na última tarefa; APNAV1Switch para ligado; e o perfil da aeronave para LowCruise, o que se desdobra em outras tarefas. Após a execução da última tarefa do estado, a pilha de tarefas estará vazia. Porém, não haverá mudança de estado até que o valor de NAVDME seja menor que 1 nm. A Figura 22 exibe a interface após a execução das tarefas. Figura 22. Execução do IAP ILS Y. Figura 23. Fim da execução do IAP ILS Y. 38 Quando a aeronave está a menos de 1 nm do VOR, ocorre a mudança de estado. As tarefas do novo estado são enfileiradas e executadas, e suas condições de mudança de estado são verificadas, a cada ciclo da aplicação.Depois de passar por todos os estados, no fim do procedimento, quando a aeronave está a menos de 3 nm do auxílio, o PA é desligado. Nesse momento, PP encerra a execução do procedimento e o aluno reassume os controles da aeronave para o pouso. A Figura 23 ilustra o fim da execução do procedimento. 39 6. Conclusão Após os estudos necessários, a implementação do módulo EasyConnect foi efetivada. Sua lista de métodos disponíveis ainda não abrange todas as variáveis e eventos oferecidos pela API do SimConnect, mas o suficiente para a execução do módulo ProcedurePerformer e seus procedimentos. Em relação ao módulo ProcedurePerformer, o parser responsável pelo carregamento de aeronaves foi implementado, assim como a estrutura dos seus arquivos de configuração. As aeronaves Mooney Bravo e Beechcraft Baron 58, sugeridas pelos livros [5] e [6] para o vôo sob IFR, já possuem seus arquivos de configuração implementados. O parser responsável pelo carregamento dos procedimentos também foi implementado, assim como a estrutura dos seus arquivos de configuração. Porém, os procedimentos baseados em auxílios NDB ainda não são suportados pela aplicação. A prioridade de implementação foi dada aos procedimentos baseados em auxílios VOR, já que os baseados em NDB não são mais usados em alguns países. Os procedimentos SID João Pessoa e IAP ILS Y, referentes ao aeroporto internacional Gilberto Freyre, já possuem seus arquivos implementados. Os recursos oferecidos pelo SimConnect para a construção de uma interface gráfica integrada com o FSX são muito limitados. A interface gráfica sugerida pelos exemplos de aplicação em C#, oferecidos pelo SDK, não é visível quando o simulador está no modo de exibição tela-cheia. A interface gráfica textual representa uma alternativa provisória para a exibição das informações do ProcedurePerformer para o usuário. 6.1. Contribuições O FlightInstructor, em seu estado atual, oferece algumas contribuições aos pilotos e desenvolvedores da aviação virtual. O EasyConnect facilita o processo de desenvolvimento de aplicações para o FSX, abstraindo os detalhes de implementação do SimConnect. Seu uso pode encorajar novos desenvolvedores a desenvolver aplicações para o simulador. Como dito anteriormente, a demanda por uma ferramenta como essa pode ser encontrada em fóruns como [19] e [20]. O ProcedurePerformer, por sua vez, mostra as etapas corretas de execução de um procedimento aeronáutico, em uma determinada aeronave, disponíveis em seu banco de arquivos de configuração. Um instrutor de vôo pode, inclusive, criar arquivos de configuração personalizados, enfocando certas particularidades do procedimento. Além disso, o potencial desse módulo não está restrito à execução dos procedimentos aeronáuticos citados no documento. O ProcedurePerformer pode ser empregado na execução de outros tipos de procedimentos aeronáuticos, que permitam o uso do PA da aeronave e envolvam componentes presentes no EasyConnect. Finalmente, um artigo sobre o FlightInstructor, escrito durante o seu desenvolvimento, foi publicado no Workshop de Realidade Virtual e Aumentada 2007, destacando a sua contribuição no meio acadêmico. 40 6.2. Trabalhos Futuros Como trabalhos futuros, o módulo EasyConnect será estendido para abranger todas as variáveis e eventos do SimConnect, possibilitando seu uso efetivo em outros projetos. O módulo ProcedurePerformer terá o seu banco de arquivos de configuração ampliado, servindo como base de exemplos para a criação de novos arquivos. Sua interface também será aperfeiçoada, permitindo a exibição da carta que representa o procedimento em execução, acompanhada do trajeto percorrido pela aeronave, entre outras melhorias. O desenvolvimento do módulo FlightAnalyzer será iniciado após a conclusão do ProcedurePerformer, e exigirá um estudo mais aprofundado sobre o processo de ensino na aviação. Seu desenvolvimento será fundamental para transformar o FlightInstructor em uma ferramenta mais abrangente. Finalmente, a validação do FlightInstructor por instrutores e pilotos será fundamental para torná-la uma ferramenta útil no meio da aviação, ajudando alunos e entusiastas a colocar em prática e aperfeiçoar os conhecimentos teóricos previamente adquiridos. 41 Referências Bibliográficas [1] The Art of Flight Simulation. Disponível em: site do Jonathan Gabbai. URL: http://gabbai.com/academic/the-art-of-flight-simulation/, visitado em janeiro de 2008. [2] Microsoft Flight Simulator X. Disponível em: site FsInsider. URL: http://www.fsinsider.com, visitado em janeiro de 2008. [3] Aeroclube de Bauru. Disponível em: site do Aeroclube de Bauru. URL: http://www.aeroclubebauru.com.br/site/base.asp?pag=tabelapreco.asp, visitado em janeiro de 2008. [4] P. O. Lima Jr., Regulamentos de Tráfego Aéreo – Vôo por Instrumento, ASA, São Paulo, 2007. [5] J. V. West, e K. Lane-Cummings, Microsoft Flight Simulator X For Pilots, Wiley Publishing, Indianapolis, 2007. [6] B. Williams, Microsoft Flight Simulator as a Training Aid, Aviation Supplies & Academics, Newcastle, 2006. [7] Computer based training. Disponível em: site da Oxford Aviation Training. URL: http://www.oxfordaviation.net/cbt.htm, visitado em janeiro de 2008. [8] Garmin G1000. Disponível em: site da Garmin. URL: https://buy.garmin.com/shop/shop.do?cID=153&pID=6420, visitado em janeiro de 2008. [9] FSFlyingSchool. Disponível em: site do FSFlyingSchool. URL: http://www.fsflyingschool.com, visitado em janeiro de 2008. [10] History of Microsoft Flight Simulator. Disponível em: site Wikipedia. URL: http://en.wikipedia.org/wiki/History_of_Microsoft_Flight_Simulator, visitado em janeiro de 2008. [11] FlightSim.com. Disponível em: site FlightSim.com. URL: http://www.flightsim.com, visitado em janeiro de 2008. [12] Carenado. Disponível em: site da Carenado. URL: http://www.carenado.com, visitado em janeiro de 2008. [13] MegaScenery. Disponível em: site da MegaScenery. URL: http://www.megascenery.com, visitado em janeiro de 2008. [14] Flight Sim Yoke e Pro Pedals. Disponível em: CH Products site. URL: http://www.chproducts.com/retail/, visitado em janeiro de 2008. [15] TrackIR 4:Pro. Disponível em: NaturalPoint site. URL: http://www.naturalpoint.com/trackir/02-products/product-TrackIR-4-PRO.html, visitado em janeiro de 2008. [16] About SimConnect. Disponível em: FsInsider site. URL: http://www.fsinsider.com/developers/Pages/AboutSimConnect.aspx, visitado em janeiro de 2008. [17] FSUIPC. Disponível em: site do Peter Dowson. URL: http://www.schiratti.com/dowson.html, visitado em janeiro de 2008. 42 [18] JSimConnect. Disponível em: site do jSimConnect. URL: http://lc0277.nerim.net/jsimconnect/, visitado em janeiro de 2008. [19] MS FSX SimConnect Forum. Disponível em: The AVSIM Forums site. URL: http://forums.avsim.net/dcboard.php?az=show_topics&forum=255, visitado em janeiro de 2008. [20] SimConnect portal. Disponível em: FsDeveloper.com site. URL: http://fsdeveloper.agerrius.nl/simconnect/, visitado em janeiro de 2008. [21] R. C. Farias, G. F. Almeida, V. Teichrieb, e J. Kelner, "FlightInstructor, um Instrutor de Vôo Virtual para o Microsoft Flight Simulator X", Workshop de Realidade Virtual e Aumentada 2007, Itumbiara, novembro de 2007. 43