Objetivo e escopo do horizonte artificial
Um horizonte artificial no sentido restrito considerado aqui é uma visualização da inclinação de um objeto em relação à vertical local, usada para controlar seu movimento. A inclinação é definida pelos valores dos dois ângulos de Euler, roll e pitch . Os marinheiros preferem o sinônimo "trim" ao termo de aviação "pitch".
Relacionado ao horizonte artificial (mas não exatamente sinônimo), termos em russo: "horizonte artificial", "dispositivo de comando de vôo". Em inglês, as expressões "indicador de atitude" , "horizonte artificial" ou "horizonte giroscópio" são usadas .
Técnicas de visualização conhecidas
A maior parte do trabalho para encontrar soluções de sucesso no campo da indicação de pitch and roll foi feita no interesse da aviação. A explicação para isso é simples: o piloto deve ler as informações rapidamente e qualquer erro em sua percepção do espaço pode ser fatal.
A maioria das soluções conhecidas no campo da indicação de rotação e inclinação são baseadas no uso de uma silhueta de aeronave e um fundo especial. Características gerais:
- o fundo é dividido em duas partes, simbolizando o céu e a terra, por uma linha que representa o horizonte;
- a silhueta da aeronave é uma visão traseira simplificada, contrastando com a cor do fundo;
- o ângulo de rotação é determinado pelo indicador como o ângulo entre a linha do horizonte simbólica e a linha que conecta as pontas das asas da silhueta (geralmente uma escala de referência está presente para uma leitura precisa);
- o ângulo de inclinação é medido ao longo de uma escala perpendicular ao horizonte condicional de acordo com a posição do ponto de controle no centro da silhueta.
Os sistemas implementados na produção em massa têm uma série de soluções comuns:
- a informação é dada pela posição relativa da silhueta e do fundo;
- a mudança no ângulo de rolagem está associada ao movimento angular da silhueta em relação ao fundo;
- a mudança no ângulo de inclinação está associada ao deslocamento linear da silhueta em relação ao fundo.
Mas não é difícil adivinhar que o movimento relativo desejado pode ser realizado de várias maneiras diferentes. Depois de muitas tentativas e erros do século passado, a evolução da aviação deixou duas combinações viáveis:
1. Silhueta fixa, movendo-se em fundo de rotação e inclinação. Nomes usados: "indicação direta", "vista do avião para o solo", menos frequentemente "indicação egocêntrica".
2. Uma silhueta movendo-se apenas ao longo do rolo, um fundo movendo-se apenas ao longo do campo. Nomes usados: "indicação reversa" e "vista do solo ao plano", menos frequentemente "indicação geocêntrica".
Observe que os nomes da cláusula 2 se aplicam ao sistema como um todo, mas refletem apenas o princípio de indicação do ângulo de rotação adotado nele. A indicação do ângulo de inclinação em ambos os sistemas usados é "reta" e "egocêntrica".
Em simuladores de vôo existentes, como o Microsoft Flight Simulator e o Digital Combat Simulator , os dois tipos de monitores podem ser vistos em ação.
É importante notar que nem todas as soluções conhecidas se enquadram no padrão acima. Para um exemplo de ir além da estrutura designada, consideremos duas patentes para invenções: RU 2561311 e RU 2331848.
A primeira patente é dedicada ao "Horizonte artificial com indicadores de inclinação e rotação espaçados em altura", seus autores: V.I. Putintsev e N.A.Lituev. O diagrama abaixo é obtido da patente.
Se necessário, você pode encontrar uma decodificação de designações e uma descrição da obra no texto da fonte original... No geral, o conceito da invenção é bastante simples: a ideia de uma “visão do solo para um avião” é realizada tanto em rotação quanto inclinação (“geocentrismo completo”), mas a indicação é dividida em dois componentes independentes.
A segunda invenção tem um nome mais complexo: "Dispositivo de comando de vôo para indicação lógica da posição e controle da aeronave no espaço." Autores da patente: A.P. Plentsov e N.A. Zakonova A ideia de indicação de pitch and roll é bastante incomum aqui.
Uma explicação das designações do circuito, uma descrição do dispositivo, uma comparação com análogos e circuitos adicionais com ligeiras diferenças de design são fornecidas na patente .
Uma coisa em comum com a invenção anterior é o conceito de geocentrismo para ambos os canais. Ao mesmo tempo, o horizonte artificial tem apenas um “símbolo de avião”, como nos modelos existentes, mas já não é uma silhueta, mas sim um modelo tridimensional - um “modelo volumétrico”. Se o movimento de rolagem for semelhante ao implementado na indicação "reversa", o arremesso e o mergulho neste dispositivo parecem originais.
Existem vários fatores que impedem a inovação no design de sistemas de exibição do mundo real. Por exemplo, um dos motivos razoáveis para o conservadorismo é o desejo de preservar a continuidade das habilidades adquiridas pelo operador, incluindo as habilidades de percepção de informações. Os jogos de computador podem proporcionar muito mais criatividade, portanto, sem nos aprofundarmos em uma análise comparativa de soluções, tomaremos como base a invenção que parece mais eficaz.
Requisitos de solução
Antes de começar a escrever o código, vamos definir a tarefa:
1. É necessário escrever a função drawAttitude () , que desenha o indicador de horizonte artificial por meio do canvas baseado na invenção de A.P. Plentsov e N.A. Zakonova.
2. A função leva o contexto do canvas , coordenadas o centro do indicador, os valores dos ângulos de rotação e inclinação em graus, o raio da face do indicador.
3. Os valores do ângulo de inclinação são limitados ao intervalo de menos 30 a mais 30 graus.
4. Os valores do ângulo de rotação são limitados ao intervalo de menos 45 a mais 45 graus.
5. Se o valor do argumento ultrapassar os especificados em p. 3 e 4 limites, o indicador mostra o valor permitido mais próximo.
Criação de função
O código de função inclui as seguintes partes:
1. Verificar os valores inseridos para exceder os limites.
2. Convertendo ângulos em radianos.
3. Escala do tamanho característico do "layout" e da fonte pelo valor do raio do indicador.
4. Componentes do desenho:
a) Corpo do indicador.
b) Layout.
c) Escalas de inclinação e rotação.
A função abaixo é escrita nesta ordem e suas partes são separadas por comentários.
Código completo
Código do arquivo HTML :
attitude.js:
<!DOCTYPE html>
<html>
<head>
<title>Attitude</title>
<script src="js/attitude.js"></script>
</head>
<body>
<canvas id="drawingCanvas" width="640" height="480"></canvas>
</body>
</html>
attitude.js:
window.onload = function () {
let canvas = document.getElementById("drawingCanvas");
let context = canvas.getContext("2d");
let run = function () {
drawAttitude(context, 320, 240, 30 * Math.sin(performance.now() / 2000), 45 * Math.sin(performance.now() / 5000), 200);
}
let interval = setInterval(run, 1000 / 60);
};
drawAttitude = function (ctx, centreX, centreY, pitch, roll, radius = 100) {
// :
if (pitch > 30) pitch = 30;
if (pitch < -30) pitch = -30;
if (roll > 45) roll = 45;
if (roll < -45) roll = -45;
// :
roll *= Math.PI / 180;
pitch *= Math.PI / 180;
// "" :
let vehicleSize = radius * 0.8;
ctx.font = Math.round(radius / 8) + "px Arial";
// :
ctx.lineWidth = 2;
ctx.strokeStyle = "Black";
// :
ctx.beginPath();
ctx.arc(centreX, centreY, radius, 0, Math.PI, false);
ctx.fillStyle = "Maroon";
ctx.stroke();
ctx.fill();
// :
ctx.beginPath();
ctx.arc(centreX, centreY, radius, 0, Math.PI, true);
ctx.fillStyle = "SkyBlue";
ctx.stroke();
ctx.fill();
//"":
ctx.beginPath();
//:
let topSideIsVisible = (pitch >= 0);
ctx.strokeStyle = topSideIsVisible ? "Orange" : "Brown";
ctx.fillStyle = topSideIsVisible ? "Yellow" : "Red";
ctx.lineWidth = 3;
//
// 4 , ,
// :
ctx.moveTo(centreX, centreY - Math.sin(pitch) * vehicleSize / 2);
ctx.lineTo(centreX + vehicleSize * Math.cos(roll), centreY + vehicleSize * Math.sin(roll) * Math.cos(pitch));
ctx.lineTo(centreX, centreY - 2 * Math.sin(pitch) * vehicleSize);
ctx.lineTo(centreX - vehicleSize * Math.cos(roll), centreY - vehicleSize * Math.sin(roll) * Math.cos(pitch));
ctx.lineTo(centreX, centreY - Math.sin(pitch) * vehicleSize / 2);
ctx.stroke();
ctx.fill();
// :
// :
ctx.beginPath();
ctx.strokeStyle = "Black";
ctx.fillStyle = "Black";
ctx.lineWidth = 1;
//:
ctx.fillText(30, centreX - radius * 0.28, centreY - vehicleSize + radius / 20);
ctx.fillText(20, centreX - radius * 0.28, centreY - vehicleSize * 0.684 + radius / 20);
ctx.fillText(10, centreX - radius * 0.28, centreY - vehicleSize * 0.348 + radius / 20);
// - :
ctx.moveTo(centreX - radius / 10, centreY - vehicleSize);
ctx.lineTo(centreX + radius / 10, centreY - vehicleSize);
ctx.stroke();
ctx.moveTo(centreX - radius / 10, centreY - vehicleSize * 0.684);
ctx.lineTo(centreX + radius / 10, centreY - vehicleSize * 0.684);
ctx.stroke();
ctx.moveTo(centreX - radius / 10, centreY - vehicleSize * 0.348);
ctx.lineTo(centreX + radius / 10, centreY - vehicleSize * 0.348);
ctx.stroke();
// :
ctx.beginPath();
ctx.strokeStyle = "White";
ctx.fillStyle = "White";
//:
ctx.fillText(30, centreX - radius * 0.28, centreY + vehicleSize + radius / 20);
ctx.fillText(20, centreX - radius * 0.28, centreY + vehicleSize * 0.684 + radius / 20);
ctx.fillText(10, centreX - radius * 0.28, centreY + vehicleSize * 0.348 + radius / 20);
// - :
ctx.moveTo(centreX - radius / 10, centreY + vehicleSize);
ctx.lineTo(centreX + radius / 10, centreY + vehicleSize);
ctx.stroke();
ctx.moveTo(centreX - radius / 10, centreY + vehicleSize * 0.684);
ctx.lineTo(centreX + radius / 10, centreY + vehicleSize * 0.684);
ctx.stroke();
ctx.moveTo(centreX - radius / 10, centreY + vehicleSize * 0.348);
ctx.lineTo(centreX + radius / 10, centreY + vehicleSize * 0.348);
ctx.stroke();
// :
ctx.lineWidth = 2;
//+-15 :
ctx.fillText(15, centreX + radius * 0.6, centreY + radius * 0.22);
ctx.moveTo(centreX + 0.966 * 0.8 * radius, centreY + 0.259 * 0.8 * radius);
ctx.lineTo(centreX + 0.966 * 0.95 * radius, centreY + 0.259 * 0.95 * radius);
ctx.fillText(15, centreX - radius * 0.75, centreY + radius * 0.22);
ctx.moveTo(centreX - 0.966 * 0.8 * radius, centreY + 0.259 * 0.8 * radius);
ctx.lineTo(centreX - 0.966 * 0.95 * radius, centreY + 0.259 * 0.95 * radius);
//+-30 :
ctx.moveTo(centreX + 0.866 * 0.8 * radius, centreY + 0.5 * 0.8 * radius);
ctx.lineTo(centreX + 0.866 * 0.95 * radius, centreY + 0.5 * 0.95 * radius);
ctx.moveTo(centreX - 0.866 * 0.8 * radius, centreY + 0.5 * 0.8 * radius);
ctx.lineTo(centreX - 0.866 * 0.95 * radius, centreY + 0.5 * 0.95 * radius);
//+-45 :
ctx.moveTo(centreX + 0.707 * 0.8 * radius, centreY + 0.707 * 0.8 * radius);
ctx.lineTo(centreX + 0.707 * 0.95 * radius, centreY + 0.707 * 0.95 * radius);
ctx.moveTo(centreX - 0.707 * 0.8 * radius, centreY + 0.707 * 0.8 * radius);
ctx.lineTo(centreX - 0.707 * 0.95 * radius, centreY + 0.707 * 0.95 * radius);
ctx.stroke();
}
O mais difícil de entender é o código para desenhar o "layout". Vamos considerá-lo com mais detalhes. Como layout, optou-se por usar uma figura plana simétrica em forma de flecha.
As superfícies superior e inferior do layout diferem entre si nas cores de contorno e preenchimento. A escolha do esquema de cores atual é a primeira parte do código.
Em seguida, o contorno da figura é construído.
A tarefa mais difícil é determinar as coordenadas das projeções dos vértices da figura no plano YOZ . Isso é o que as expressões com funções trigonométricas resolvem. Os vértices no código são percorridos na ordem de sua numeração na figura.
A maior parte do código é dedicada a escalas e assinaturas. As marcas de escala têm muitas diferenças: superior e inferior, esquerda e direita, com e sem rótulos. O impressionante número de linhas deve-se à escrita do código "individual" de cada elemento.
As funções trigonométricas dos ângulos correspondentes são usadas para aplicar marcas de rolagem. Uma vez que os valores dos ângulos de cada rótulo são conhecidos com antecedência, valores prontos de senos e cossenos são escritos no código.
É melhor avaliar a aparência do indicador na dinâmica. Com a ajuda da nova função, mostramos as oscilações de pitch e roll. Para a máxima variedade de posições, façamos as amplitudes de oscilação correspondentes aos limites do indicador e os períodos - diferentes e mutuamente simples.
Conclusão
A rigor, o código acima para a visualização de rotação e inclinação deve ser chamado de uma indicação "baseada na" invenção de A. P. Plentsov e N. A. Zakonova. Alguns desvios dos esquemas originais são feitos para simplificar o problema, outros para melhorar a implementação.
O indicador apresentado está longe de ser ideal em termos de design. As limitações aceitas dos valores exibidos não são ideais para nenhum critério objetivo. No entanto, a tarefa de criar um demonstrador de tecnologia interessante pode ser considerada resolvida.