Como escrevo testes de unidade para robôs (e outros dispositivos mecânicos)?

22

Sou membro do clube de robótica da minha escola e sou responsável pela programação do robô. Uma sugestão que continuo ouvindo de vários adultos é que eu deveria escrever testes de unidade para ajudar a validar meu código. A base de código está ficando um pouco grande, e eu concordo que os testes de unidade seriam realmente úteis para me ajudar a detectar erros mais rapidamente.

No entanto, não tenho muita certeza de como conseguir isso. De acordo com o meu conhecimento, o teste de unidade é realizado usando uma função (ou um subsistema do código) e alimentando-o com um conjunto de entradas para garantir que ele saia com a mesma saída a cada vez. O código que eu tenho atualmente não faz nenhum processamento pesado de dados, mas manipula diretamente os componentes de hardware no robô. A maior parte da complexidade vem de garantir que os componentes eletrônicos sejam sólidos, que o código no momento corresponda ao hardware real do robô etc. Muitas vezes, só consigo ver se há algum problema carregando o código no próprio robô, e tentando executá-lo.

Por extensão, como os testes de unidade podem ser escritos para códigos destinados a operar qualquer dispositivo mecânico? Parece-me que você só pode detectar erros observando fisicamente o funcionamento da máquina.

Ou estou apenas entendendo mal como os testes de unidade devem funcionar?

( Se importa, aqui está o código , está escrito em C ++ e estou participando do FRC )

Michael0x2a
fonte

Respostas:

21

Você precisará zombar da camada de hardware para fazer esse teste. A idéia é que, em vez de seu código falar com o hardware real, você converse com uma versão falsa do hardware que você pode controlar e depois use para verificar se seu código está funcionando corretamente.

Infelizmente, existem alguns problemas que você precisa superar:

  • Zombar de coisas em idiomas de nível relativamente baixo é mais difícil (e, portanto, muito mais trabalho)
  • Zombar de coisas no nível do hardware é mais difícil (e, portanto, muito mais trabalho)

Além disso, a maior parte do valor do teste de unidade automatizado vem da capacidade de executar seus testes a qualquer momento para detectar erros de regressão por longos períodos após a gravação do código original. Com esse tipo de competição, seu código não será usado depois que o concurso terminar, para que você não aproveite ao máximo o valor dos testes. E considerando a dificuldade de adicionar testes ao seu caso em particular, pode ser melhor usar seu tempo apenas para fazer testes manuais e se concentrar nos recursos do concurso.

Oleksi
fonte
1
Boa resposta. Especialmente sobre o fato de que o código não será usado após a competição e que o grande benefício dos testes de unidade automatizados ocorre bem depois que os testes foram escritos. Você pode considerar automatizar alguns de seus testes no caso em que se encontra executando o mesmo teste repetidamente; mas até que isso aconteça, não há muito sentido.
Dawood diz que restabelece Monica
Não é necessário zombar do hardware. Se o robô tiver registro, execute o programa de teste e observe os registros. O teste final precisa de observação "virar à esquerda" no registro deve corresponder ao robô que vira à esquerda. Você terá que escrever um equipamento de teste para zombar os dispositivos de entrada - ligar o código de dispositivo de entrada tão perto da camada de hardware quanto possível
mattnz
4
@DavidWallace Como um pouco de reflexão, ao usar o TDD / BDD, os benefícios do teste de unidade ocorrem imediatamente. Em primeiro lugar, permitindo que o código seja refatorado com confiança imediatamente e, em segundo lugar, incentivando a implementação a se limitar à implementação mínima necessária para satisfazer os testes.
S.Robins
4
@mattnz má idéia, e eu sei por experiência própria. E se o código em teste falhar muito e o robotarm bater contra a parede, arruinando um pedaço de hardware xxxx $ ???
stijn
2
@mattnz: Nossos robôs têm cerca de 2 pés por 3 pés por 4 pés e pesam cerca de 150 libras. O kit / registro custa 5 mil dólares a cada ano, e geralmente arrecadamos outros 5 a 10 mil para comprar peças adicionais. O pior cenário provavelmente custaria mais de US $ 10;)
Michael0x2a
10

Eu posso pensar em algumas coisas que você precisará considerar. O primeiro é tornar a camada de acesso ao hardware o mais fina possível, mesmo que isso signifique a criação de uma camada básica do tipo wrapper para ela. Isso oferece algumas vantagens. A primeira é que ela permite isolar os comportamentos específicos do hardware do seu código do próprio acesso ao hardware, o que significa que você pode testar tudo até a parte inferior das comunicações do hardware sem precisar acessar o próprio hardware.

Por exemplo, se você precisar projetar um protocolo de sinalização baseado em I2C, poderá testar se seu código está gerando os sinais I2C corretos sem precisar conectar o hardware aos testes.

Para chamadas para o hardware real, você pode testar se elas estão se comportando corretamente, zombando da camada de hardware, e é aqui que a manutenção de uma camada de hardware muito fina realmente compensa, porque você pode reduzir a simulação para precisar apenas lidar com as funções mínimas necessárias para realmente aborda o hardware, mas você não precisa necessariamente testar os sinais individuais, pois toda a sua sinalização deveria ter sido testada em um nível superior. Isso significa que você usa o seu mock para verificar se são feitas chamadas para métodos de hardware específicos que fazem com que seus sinais sejam enviados ao hardware. Se você precisa pesquisar seu hardware, seu mock precisa ser capaz de acionar eventos ou métodos apenas no seu código, porque, novamente, sua sinalização de retorno deve ser tratada em uma camada superior.

Isso se encaixa basicamente no que Oleksi disse em sua resposta , já que geralmente é mais trabalhoso zombar de coisas no nível de hardware, no entanto, não é tão difícil se você mantiver a camada de código mínimo / chamada possível mais enxuta possível hardware.

Quando você tem um código que passa em todos os seus testes, ainda será necessário executar uma série de testes manuais para garantir que você tenha ocultado tudo corretamente na sua camada de hardware.

A outra coisa que vem à mente, além da zombaria e da estratificação, é usar uma prática de desenvolvimento de teste primeiro. Essencialmente, você codifica seus requisitos como critérios de teste e baseia sua implementação em seus testes. Isso ajudará você a garantir que você mantenha seu código de implementação no mínimo, garantindo que todos os seus casos de teste estejam direcionando seus esforços de desenvolvimento. Por não perder muito tempo com outro código potencialmente não crítico que você pode ser tentado a fazer "apenas porque", o teste ajuda a manter o foco e facilitará a alteração do código durante a depuração, assim como o uso de seus testes de unidade e zombarias. A depuração de bugs de software através do hardware é notoriamente complicada e consome grandes quantidades de tempo que você gastaria melhor em outras tarefas.

S.Robins
fonte
2

Posso dizer como eles fazem isso no Flight Simulators

Primeiro, você só receberá metade da resposta se fizer essa pergunta apenas aos programadores. Por isso, provavelmente você deve postar isso em http://electronics.stackexchange.com enquanto estiver fazendo isso.

Eu não fiz nenhum trabalho com robôs, mas passei 5 anos desenvolvendo hardware em simuladores de vôo para poder dizer como a arquitetura deles funciona.

A camada de hardware é burra

Ele contém uma interface básica onde você pode ajustar valores simples de entrada / saída e definir pontos de interrupção de interpolação para sinais analógicos. Quando você trabalha com hardware 'novo', tudo funcionará conforme o esperado, com pouca ou nenhuma calibração, mas com o tempo as peças sofrerão desgaste mecânico e precisarão ser ajustadas.

A calibração é uma tabela simples que contém seções variadas entre os valores mínimo / máximo. Para medir a entrada neles, normalmente é usado um servo (por exemplo, um potenciômetro linear, transdutor, acelerômetro, etc.). Ou, no caso da instrumentação, você apenas julga a precisão visualmente e ajusta até calibrar.

A camada de software é o oposto

Tudo é complexo e interconectado, por isso é importante isolar algumas variáveis ​​para testar a funcionalidade. Não é necessário ter dor de cabeça ao pensar em cenários, porque é muito mais fácil executar alguns cenários realistas onde você pode coletar dados. Quando você executa os testes, está basicamente medindo os dados armazenados em relação à saída atual.

Em um simulador de vôo, isso é chamado de QTG (Qualification Test Guide). Em sua essência, ele plota os dados em uma grade 2D, onde uma dimensão é o tempo e a outra é a saída.

Acredite ou não, essa é a essência de como eles desenvolvem os modelos. Um avião real é equipado com uma tonelada de sensores e voa por aí fazendo cenários controlados. Como todos os controles podem ser controlados sem interação humana, os testes são executados (ou seja, o sim voa) pelo computador e os dados são comparados.

Embora a robótica seja criada em uma escala muito diferente, os princípios são os mesmos. A abordagem tradicional é cortar completamente as camadas de hardware e software para que ambos possam ser testados individualmente. A entrada de hardware é coletada através de servos e definida através de uma interface independente. A entrada do software pode ser configurada / lida medindo e comparando independentemente a sinalização que, de outra forma, seria direcionada ao hardware e plotando-a em relação a dados 'bons' conhecidos.

Os testes em si não precisam necessariamente ser complexos, desde que os resultados sejam previsíveis, mensuráveis ​​e reprodutíveis.

Evan Plaice
fonte
1

Como dito anteriormente, zombe e remova as peças de hardware. Como exemplo, se você possui uma interface para o robô, pode herdar dessa interface e fazer implementações de stub simples. Em seguida, você pode testar se a implementação do stub foi chamada conforme o esperado. Se isso é esperado funções ou parâmetros esperados.

martiert
fonte