Raspberry

Dicas de desenvolvimento em Qt no Raspberry

Qt no Raspberry

Vou tomar como base o Raspberry Pi, porque tenho 22 anos de experiência com Linux e isso facilita muito as coisas, de modo que tomo meus próprios caminhos na dissolução de problemas e eventualmente preciso pesquisar sobre alguma questão específica. De qualquer modo, é praticamente impossível não precisar fazer pesquisas no desenvolvimento em sistemas embarcados, conforme explicarei no decorrer do artigo sobre Qt no Raspberry.

Atualização do Raspbian

Uso o Raspbian por ser uma compilação de Debian para ARM e em servidores é o sistema que tenho utilizado desde 2006, aproximadamente.

Nem sempre é uma boa ideia atualizar o sistema, pois a base de diversos recursos de sistema podem mudar. Símbolos, comportamentos, recursos que se modificam. Um bom exemplo de um problema que eu não tinha (e que já esperava, devido à experiência anterior) é em relação ao programa que estou desenvolvendo em Qt com QML e QtQuick. Já programo há anos em Qt, mas sempre fui resistente ao modelo MVC (tentarei discorrer a respeito mais adiante).

Se o desenvolvimento já estiver em andamento e alguma necessidade pontual aparecer, pode ser melhor tentar resolver a dependência através do gerenciador de pacotes, usando repositório de software adicional ou compilando o recurso do Qt no Raspberry manualmente. Como eu não tinha o compromisso de prazo, não me incomodei em atualizar o Raspbian de Stretch para Buster. E achei até fundamental, porque a versão padrão do Qt no Stretch é a 5.7.1, enquanto no Buster é a 5.11.3. Como estou tentando fazer um software utilizando os recursos do sistema para simplificar em um artigo (exceto queira realmente fazer cross compile ou compilação nativa) peguei um outro cartão para tentar utilizar o Qt nativo e ver o que ele oferecia. Essa diferença de versão entre uma versão e outra do Raspbian é gritante.

Faça o update

Primeiro passo para uma atualização com sucesso (considere que pode não funcionar em todos os casos) é atualizar os pacotes já instalados. Para tal:

Após atualizar o sistema, reinicie. Ao reiniciar, edite o arquivo de repositórios do apt e modifique stretch para buster. Deve ficar assim:

Agora, um novo update é necessário e após isso, iniciamos o upgrade do sistema:

Se estiver fazendo a atualização por ssh, pode ocorrer a perda de comunicação por um período variável, tenha paciência.

Alguns serviços de sistema terão seus arquivos de configuração substituídos, mas isso é questionado durante a instalação dos pacotes. Se houver personalização nos respectivos serviços, mantenha a versão já instalada.

Quando terminar a atualização, reinicie. Provavelmente o sistema ainda estará funcionando.

Depuração de funcionalidades

Vou primeiro ao problema que ocorreu.

A atualização de sistema trouxe benefícios e malefícios. Tendo a sugerir o início do desenvolvimento no sistema previamente atualizado, mas alguns recursos importantes não estavam disponíveis na versão padrão do Qt no Raspberry com Raspbian Stretch.

Avalie se os recursos necessários são funcionais

Após a atualização, recursos do programa deixaram de funcionar. A maioria deles, relecionado ao código C++ do programa. O programa sequer iniciava, de cara dava falha de segmentação. E para descobrir?

O primeiro passo foi criar uma nova aplicação com o básico de QML e compilar. Como era um projeto só com a “carcaça”, já serviria para saber se haveria de funcionar o EGLFS, que é o backend que utilizo para rodar o programa sem servidor gráfico. Funcionou, portanto o problema era relacionado a alguma particularidade do meu código – acho.

Use alguma forma de depuração do Qt no Raspberry

Como pegar traços do que pode estar ocorrendo no sistema? Bem, o arquivo main.qml pode ser um ponto de partida. Coloquei “prints” em alguns pontos. Percebi que ele era carregado adequadamente, portanto o problema não era relacionado ao view ou ao model, mas ao controller.

Como meu código C++ tem acesso aos elementos da interface, desabilitei todas as chamadas e posteriormente fui reabilitando. Isso foi fácil porque costumo programar de forma modular, bastando desabilitar uma recurso e o restante do código não é afetado.

Ao desabilitar as chamadas aos objetos da interface, o programa iniciou. Ótimo! É muito mais fácil resolver um problema identificado do que um problema incerto. Mas o touchscreen deixou de funcionar. E agora? É driver? É sistema? É programa?

Para resolver essa questão, é fundamental saber que recursos do sistema o programa utiliza e conhecer esses recurso do sistema. No caso, eu sabia que estava utilizando os eventos gerados pelo sistema em /dev/input/*. O touchscreen é o dispositivo event0 no meu sistema. O dispositivo existia. Mas estava funcionando? Fácil saber:

Desculpe pela transparência no terminal, mas eu gosto.

Repare que utilizei o comando cat nativo do sistema, apontando para o dispositivo /dev/input/event0. Ele fica travado porque é um dispositivo de caractere, o que significa que não tem “final de arquivo”. Os dispositivos em Linux são arquivos descritores, se não tiver esses conceitos, é bom dar uma estudada.

Com esse comando, comprovei que o touchscreen estava funcionando no sistema. Ótimo, meu programa só precisa estar lendo esses eventos. Como saber se o programa está interagindo com os eventos da tela? Para isso, utilizei o comando strace:

Como tenho um relógio na tela atualizando segundo a segundo, já sei que a tela não está travada. Sempre coloque um evento visual para ter feedback da aplicação, ainda que seja aplicação final. Nada como olhar para a tela e ter um diagnóstico inicial.

Agora, ao tocar na tela, os eventos de interação do Qt com o sistema deve aparecer na tela. O programa estava recebendo eventos do display, menos mal.

A documentação também diz que é necessário ter as bibliotecas de desenvolvimento da libinput ou tslib, conforme o que for utilizado.

Para adiantar o processo, invés de caçar um a um os problemas, tentei resolver instalando o máximo possível dos pacotes relacionados aos eventos. No caso, a documentação diz que é utilizado o evdev e a libinput, como citei anteriormente. Portanto, fui instalando pacotes supostamente relacionados. Em caso de sistemas que venham a ser produto, claramente é fundamental saber a origem do problema de forma pontual, mas na informalidade de um passatempo, a preguiça fala mais alto. Não precisa reproduzir essa parte, estou apenas mostrando o que fiz:

Para tentar usar o evdev, configurei a variável de ambiente que desabilita a libinput:

Nada, só funcionou com a libinput, mas isso já ajuda  a perceber que realmente os eventos ocorrem com a libinput. O problema não pode estar relacionado ao touchscreen. Voltei a variável de ambiente para o valor 0 e segui adiante.

Esses testes devem consumir 20 minutos ou um pouco mais. Após as tentativas frustradas, ainda restava a possibilidade de usar um programa dos exemplos. Ao menos esse deveria funcionar e assim garantir que o problema era na minha aplicação. Utilizei o Qt/Examples/Qt-5.13.0/widgets/touch/fingerpaint/, que também não funcionou. Onde estará o problema?

Variáveis de ambiente

Pra saber como está configurado o Qt no Raspberry, podemos usar o comando qtdiag:

Plugins instalados

Ainda analisando o ambiente, onde estão e quais são os plugins disponíveis no sistema? Para descobrir, usamos o comando:

Daí uma listagem no diretório mostrará algo como:

qt modules

No diretório platforms temos todos os backends suportados, mas chamar o executável do programa com os parâmetros -platform ? retornará essa informação.

Diretório de binários

Utilizando o mesmo programa com o parâmetro –binaries-dir encontramos o diretório de binários usado no sistema, no qual se encontram diversas ferramentas que podem auxiliar em casos específicos:

qtpaths binaries

Instalando pacotes relacionados a tslib

Ainda restaram algumas possibilidades. Instalei alguns pacotes extras:

O programa evtest serve para confirmar o dispositivo. Após executá-lo, aponte o número para o dispositivo da lista. No caso, 0. Depois é só tocar na tela e ver o resultado. Mas já havia confirmado isso de outras formas anteriormente.

Mais um teste (são apenas opções, uma já é mais que o suficiente para diagnóstico):

Compilar a tslib

Ok, até agora nada resolveu o problema. A tslib instalada pelo apt não tem todos os requerimentos necessários para funcionar, por isso resolvi compilar.

A compilação será um processo lindo e direto. Não é assim, normalmente.

Quando escrevo artigos, gosto de fazer experimentos primeiro e assim disponibilizar algo realmente funcional. Para chegar nessa compilação, tive diversos problemas que, se os colocasse no artigo, talvez você desistisse da leitura.

O display já estava funcional em relação ao sistema operacional, mas por alguma razão, não o estava no Qt. Compilar a tslib foi uma opção para tentar outra API. Após o processo acima, o primeiro passo foi testar a resposta do display, que virou event3:

 

E ao passar o dedo na tela, a resposta ocorreu normalmente. Esse teste tem uma interface feia, mas o que importa é saber se está funcionando, porque se não estiver no sistema, não estará no Qt:

Qt no Raspberry - tslib console

Os testes mostraram o display responsivo, mas o problema ainda não foi sanado. A tslib tem uma outra ferramenta para fazer o teste gráfico, então percebi que realmente havia um problema com a interface entre o sistema. Ao tocar na tela, o cross-hair sumiu. Os botões não respondiam, logo, outra coisa não estava funcionando adequadamente.

Qt no Raspberry - tslib

Mas será que o primeiro toque tem algum efeito? Bem, reinicie o ts_test e cliquei sobre o botão Drag. Daí apareceu o cursor, lá no final da tela, ou seja, a partir da atualização se fez necessário calibrar o display.

Utilizei o ts_calibrate para ajustar, depois rodei novamente o ts_test. Tudo aparentemente funcionando agora, exceto o programa em Qt.

Nessa hora que se destaca a importância de fazer sua própria compilação. Pelo visto, não tem suporte a libts na compilação padrão do Qt para Raspberry. A libinput está funcionando também, portanto, ainda há um longo trabalho pela frente.

Instalar o Qt no Raspberry

Para continuar o desenvolvimento de onde parei enquanto não resolvo essa questão, instalei o sistema em um novo cartão e em seguida instalei o Qt novamente, na versão 5.7, padrão do Raspbian Stretch. Após acessar o Raspbian:

Compilar um módulo específico do Qt

Ainda há uma opção extra, caso deseje utilizar algum módulo que não esteja no repositório de pacotes, mas esteja disponível no branch da versão que estiver utilizando.

Substitua a opção modulo pelo módulo que deseja utilizar, e a versão do Qt pode ser identificada com o qmake:

Qt no Raspberry - versão do qmake

Para saber o nome correto do módulo que deseja instalar, pode-se fazer uma consulta no “cardápio” disponível nesse link.

Apenas a título de exemplo, supondo que queira o QtMQTT:

Nem tente esse processo na versão 5.7.1, porque o módulo MQTT não está disponível nela.

Quando eu der continuidade à busca pela solução, escrevo outro artigo com os resultados e o processo para tal.

Vídeo

Se desejar dar uma conferida na interface que estou fazendo com Qt, QML e Quick, clique nesse link. A interface de 3 abas é essa cuja uma das abas é a imagem de destaque.

Aproveite para se inscrever no canal, clique no sininho para receber notificações, deixe seu like e se desejar tutoriais para produzir interfaces como essa, comente lá no vídeo ou em nossa página no facebook.

Display 5 polegadas 800×480

Esse display bacana é do nosso parceiro Baú da Eletrônica, cujo artigo relacionado você encontra nesse link. O tutorial mostra a maneira mais simples de configurá-lo, sem precisar instalar nada para ter o touch funcionando!

O link direto para o produto é esse.

Até a próxima!