O bug aeroespacial
O bug que explodiu um foguete
Explorar o espaço virou uma rotina tão comum, que os avanços tecnológicos feitos não são mais noticiados com tanta ênfase. Só no final de 2018, por exemplo, a NASA conseguiu pousar a sonda Insight em Marte,que agora está atuando como uma base pra estudar seu interior.

Usamos um braço robótico pra colocar um sismômetro no solo de Marte, que não só vai ouvir, mas também medir impactos de asteroides, deslizamentos de terra e terremotos. Saber a frequência e a intensidade de martemotos é algo importantíssimo pra que a gente possa começar a pensar sobre como vamos construir os nossos conjuntos habitacionais por lá em breve.
Além disso, a Insight cavou um buraco de 5 metros de profundidade durante 3 meses para verificar quanto calor Marte deixa escapar.

Aqui na terra bastante coisa também aconteceu: a Estação Espacial foi reabastecida com os foguetes da SpaceX, e em Alcântra a Força Aérea Brasileira levou cinco experimentos a 120km de altitude com sucesso. O que não deu muito certo foi a volta do foguete que foi à Estação Espacial, que ao tentar pousar, teve um problema em um dos estabilizadores e começou a sair de controle. Devido a uma incrível resistência estrutural e algoritmos de controle, no entanto, o foguete se dirigiu ao mar onde foi então recuperado sem maiores danos.
Esses acontecimentos, servem como lembrete do quão difícil é explorar o espaço, com coisas inesperadas podendo acontecer a qualquer momento e pelas mais fúteis razões. Nesse texto, vou retratar um caso que aconteceu com a Ariane 5, um foguete que custou 7 bilhões de dólares para ser construído e que explodiu após 39 segundos de seu primeiro voo, um prejuízo absurdo, que poderia ter sido salvo com algumas linhas de código a mais.
Para entender como lidar com falhas inesperadas, vamos começar escrevendo um programinha simples, que irá pegar dois números inteiros e então dividi-los pra nos dar um resultado. Com isso, já temos tudo que precisamos para escrever um método em Java que calcula exatamente isso:
public class Div {
static int divisao(int a, int b) {
return (a/b);
}
public static void main(String args[]) {
System.out.println(divisao(25, 5));
System.out.println(divisao(40, 2));
System.out.println(divisao(100, 10));
}
}
No código acima, fazemos uma divisão comum, (25 por 5, 40 por 2 e 100 por 10). Como você pode ver, o nosso programa parece estar funcionando. O problema é que esquecemos de certos detalhes! Por exemplo: ao digitar 1 dividido por 2, obtemos 0 ao invés de 0.5 porque a divisão de números inteiros em Java sempre arredonda para baixo.
Para resolver o problema acima, vamos introduzir no nosso código números flutuantes, que são abreviados como “floats”. Números salvos dessa forma conseguem representar números racionais através do deslocamento do “.” que separa a parte inteira da parte fracionária de um número, usando a notação científica. O código vai ficar assim:
public class Div {
static float divisao(float a, float b) {
return (a/b);
}
public static void main(String args[]) {
System.out.println(divisao(25, 5));
System.out.println(divisao(40, 2));
System.out.println(divisao(100, 10));
System.out.println(divisao(1, 2));
}
}
No nosso exemplo, o ponto flutua completamente para fora e no lugar é feita uma multiplicação com 10 elevado a -1, nos dando o resultado esperado: 0.5. Aumentamos a precisão dos resultados no nosso programa usando floats. Se você souber como contar em binário, e isso é importante agora no sentido de que quanto mais bits temos para representar um número float, maior será sua precisão também. No momento estamos programando com um float de 32 bits, mas Java nos dá a possibilidade de umsar um “double”, que tem 64.
Similarmente, existe um tipo de número inteiro chamado “short” (curto, em inglês) que usa 2 bytes ao invés de 4. Transformar um número de um tipo para outro é possivel, mas pode levar a imprevistos que vamos entender agora.
Como cada bit pode segurar 0 ou 1, dois bytes, 16 bits, servem para descrever 2¹⁶ números distintos. Dividindo essas 65,536 possibilidades por dois, conseguimos descrever valores que vão de -32,768 a 32,767. Simplismente fingimos que números maiores do que isso não existem. Mas se por algum motivo nosso programa retornar um valor maior do que isso, como por exemplo 42 mil, temos que realizar uma operação chamada casting, que pega nosso short de 2 bytes e transforma em um int de 32. Magicamente, temos um novo intervalo muito maior no qual 42 mil se encontra, e seguimos felizes.
Sem essa operação, nosso número teria estourado os limites estabelecidos, transbordando pra território desconhecido. (chmam isso de overflow)
Em programação nossa linha númerica na realidade é um círculo, então esses 32,767 + 1 resultariam em -32,768. É por causa desse círculo que fazer o contrário (o casting de 42 mil para um short, no qual ele não cabe) resulta em um número negativo. Os primeiros 32 mil dos 42 mil cabem, e o resto transborda para outra metade negativa do círculo. Uma forma de lidar com isso é com exceções.
Uma condição da qual não nos protegemos ainda é o que ocorre ao dividir por 0, um erro fatal acontece. Portanto, podemos envolver essas linhas em um bloco que vai tentar executar nosso código, mas se algo der errado, dizer que algo inesperado aconteceu e terminar o programa de forma segura.
public class Div {
static float divisao(float a, float b) {
try {
return (a/b);
} catch (Exception e) {
System.out.println("Deu ruim, você dividiu por 0!");
return Integer.MAX_VALUE;
}
}
public static void main(String args[]) {
System.out.println(divisao(1, 0));
}
}
Agora o nosso programa finalmente funciona da maneira esperada! Esses blocos que cuidam de exceções conseguem nos proteger de diversos bugs, e a falta deles foi em parte responsável pelo acidente da Ariane 5.
A ideia por trás do desenvolvimento da Ariane 5 pela Agência Espacial Europeia foi substituir a Ariane 4 com um foguete mais potente, capaz de levar cargas muito maiores ao espaço como por exemplo dois satélites de três toneladas cada. Com isso, a Europa estava prestes a se tornar referência na exploração espacial comercial após o investimento de 7 bilhões de dólares (27 bilhões de reais) e 10 anos de pesquisa. Nesse primeiro voo, quatro satélites sem seguro no valor de 500 milhões de dólares estavam sendo levados. A trajetória do voo em si estava sendo controlada por um computador a bordo, que 36.7 segundos após o lançamento pensou que uma correção de curso precisava ser feita devido a dados muito estranhos que o sistema de orientação inercial estava recebendo, vindos de instrumentos como acelerômetros e giroscópios. Esses dados bizarros e impossíveis na realidade eram uma mensagem de erro que foi interpretada como informação válida, o sistema em si tinha caído e estava inoperante.
Esse desligamento foi causado por um overflow na conversão da velocidade horizontal do foguete (que estava sendo salva em um float de precisão dupla, com 64 bits) para um numero inteiro de 16. Imitando esse mesmo problema no nosso programa com 84 mil dividido por 2, por exemplo, vemos que recebemos esse mesmo resultado absurdo de antes ao invés de 42mil pois o valor simplesmente não cabe em 16 bits.
public class Div {
static short divisao(double a, double b) {
return (short) (a/b);
}
public static void main(String args[]) {
System.out.println(divisao(84000, 2));
}
}
#Exemplo do código do foguete
Essa parte do código do foguete não estava protegida por exceções porque os engenheiros basicamente reaproveitaram o código da Ariane 4, que era fisicamente incapaz de alcançar uma velocidade horizontal tão alta!
E o pior: esse cálculo todo em si não tinha mais utilidade nenhuma após a decolagem, sua função era de apenas garantir que tudo estava em ordem antes do lançamento. Mas já nas versões anteriores da Ariane os programadores decidiram dar uma tolerância de 40 segundos, para facilitar reinicializações do sistema caso houvesse pequenos atrasos durante a contagem regressiva. Ou seja: durante o desenvolvimento dos foguetes mais antigos, ninguém imaginava que o código fonte seria simplesmente reutilizado nas versões seguintes.
E os cientistas trabalhando no foguete mais moderno, vendo porçoes de um programa que não é usado, deixaram de testar essa parte mas também não a tiraram porque isso pode causar uma série de problemas adicionais. Com o processador da nave já tão sobrecarregado, para que gastar recursos computacionais cuidando de exceções em trechos que não deviam nem ser executados em primeiro lugar?
Depois que o sistema desligou, o controle foi repassado a um backup que era completamente redudante por ser uma cópia exata, levando ao mesmo erro meros milissegundos depois. Com isso, o foguete fez uma correção de curso que não era precisa, compensando por um movimento errado que não tinha ocorrido. A partir desse ponto, a Ariane 5 nada mais era do que um míssel com um alvo surpresa. As forças envolvidas começaram a despedaçar o foguete, que então corretamente acionou a rotina de autodestruição devido aos estresses aerodinâmicos que estavam arrancando os propulsores.
E foi assim que a quatro quilômetros de altitude, sobre os pântanos da Guiana Francesa, o que deve ter sido a queima de fogos de artifício mais cara da história aconteceu.

Hoje, a Ariane 5 é um dos foguetes mais confiáveis, tendo 97 de seus 102 lançamentos efetivos. Explorar o espaço dá trabalho e é difícil, mas a longo prazo definitivamente vale a pena.
O maior desafio é fugir do efeito borboleta, que como foi aqui fez com que um pequeno erro, fosse sendo ampliado ao ponto de causar perdas bilionárias.
Obrigado por ler meu texto!
Se você chegou aqui, significa que eu te entreti!
Não fique com medo de me mandar um email!
diego.luidiblu@gmail.com