Comunicação serial com Arduino utilizando Qt5 Console Application

Introdução

 

Fiz um post há um tempo sobre como realizar comunicação serial utilizando o Python (Python + Arduino - Comunicação Serial [1]) e para facilitar utilizei um Arduino UNO. Desta vez vamos conhecer o Qt e verificar o que precisamos e as opções disponíveis para comunicarmos. Podemos fazer uma aplicação simples, para interação via console apenas, ou com interface gráfica.

 

Para familiarizarmos com o Qt, tem um post que escrevi há um tempo (Qt5 - Conhecendo um verdadeiro canivete-suiço [2]) e aborda com bastante detalhes essa ferramenta. Para quem nunca teve contato e quer instalar o Qt, pode usar este outro post, Qt5 - Instalação em ambiente Linux [3], com passo a passo para instalar o QtCreator no Linux. Mesmo quem já instalou é interessante ver o post para entender as opções que podem ser habilitadas antes da instalação.

 

 

Configuração do ambiente host

 

Para este artigo será utilizada a distribuição Linux Mint 17 Qiana 64 bits, mas sem problemas em utilizar um Ubuntu ou Debian. A seguir são listados os seus pré-requisitos:

  • Qt5 Instalado com o Qt Creator;
  • IDE Arduino 1.6.2;
  • Arduino UNO;
  • Plugin Qt Serial.

 

 

Qt5 Console Application

 

A abordagem neste post e na série que está por vir, o Qt5 será utilizado em ambiente Linux e com desenvolvimento de aplicação para Linux (x86 ou arm), porém Qt5 pode ser instalado tanto em Windows, Linux ou MacOS, além de poder ser compilado para outras plataformas.

 

Sem mais delongas, se você já instalou o Qt5 pode abrir o Qt Creator, e caso ainda não tenha instalado confira o procedimento do post Qt5 - Instalação em ambiente Linux [3].

 

Com a IDE do Qt aberta, click em File > New File or Project... e uma janela como na Figura 1 surgirá e você deverá escolher Applications > Qt Console Application e clicar em Choose .

 

Qt5_criando_projeto_console01_embarcados.com.br

Figura 1 - Criando Projeto Qt Console

 

Na janela seguinte devemos dar um nome ao projeto (Name:) e dizer onde deverá ser salvo (Create in:) como na Figura 2. No meu caso escolhi salvar na pasta /tmp/ apenas para este artigo, mas você poderá criar uma pasta no seu /home e salvar nela. 

 

Qt5_criando_projeto_console02_embarcados.com.br

Figura 2 - Nome e localização do projeto

 

Na etapa seguinte vamos apenas confirmar se estão selecionadas as opções como a da Figura 3, não precisa ser igual mas atente sobre o GCC. Quando criar o post de projetos Qt para embarcados esta etapa será abordada com mais detalhes. Para avançar clique em Next.

 

Qt5_criando_projeto_console03_embarcados.com.br

Figura 3 - Selecionando o kit de desenvolvimento (Build)

 

Na janela seguinte da Figura 4 será onde você deve ou não escolher o software de versionamento (Git, Bazaar, Mercurial, CVS, Subversion, entre outros). No caso do artigo não estarei usando, mas quando for utilizar um projeto do Qt, por favor utilize uma das opções, quem for dar manutenção no futuro ira agradecer. Logo abaixo será exibido um resumo sobre o nome do projeto e o local que será salvo. Se estiver de acordo é só clicar em Finish.

 

Qt5_criando_projeto_console04_embarcados.com.br

Figura 4 - Versionamento

 

Uma estrutura como na Figura 5 é para ser criada, onde temos o nome do projeto em primeiro nível, logo em seguida algumas diretivas que podemos passar para o Qt, e Sources e Headers, que são os diretórios dos arquivos fontes. Neste caso apenas Sources com o main.cpp já criado pelo Qt.

 

Para entender melhor sobre esta estrutura e as opções que surgiram na coluna ao lado, veja o post Qt5 - Conhecendo um verdadeiro canivete-suiço [2].

 

Qt5_criando_projeto_console05_embarcados.com.br

Figura 5 - Tela inicial Qt Console

 

Maravilha, estamos com a IDE instalada, projeto criado e o passo seguinte será configurar para comunicação serial e criar nosso primeiro programa.

 

 

Plugin QtSerialPort

 

Caso você tenha realizado a instalação do Qt5 conforme mencionei no Qt5 - Instalação em ambiente Linux [3], você selecionou qtserialport e estará tudo certo. Você pode obter informações no link QtSerialPort [4]. Primeiro iremos adicionar no arquivo .pro a seguinte entrada.

 

Qt5

 

Qt4

 

Como sei que muitos desenvolvedores ainda utilizam o Qt4 (4.8) tentarei guiar o post para as duas versões. No caso do Qt5 pode ser visto na Figura 6.

 

Qt5_criando_projeto_console06_embarcados.com.br

Figura 6 - Configurando QtSerialPort no .pro

 

O próximo passo é incluir as bibliotecas básicas para trabalhar com o QtSerialPort, como pode ser visto na Figura 7, linhas 2 e 3.

 

Qt5_criando_projeto_console08_embarcados.com.br

Figura 7 - Adicionando as bibliotecas do QtSerialPort ao projeto

 

Vamos construir o projeto, clicando em Build Project (Ctrl + B), o ícone com um martelo desenhado, e devemos ter uma saída Compile Output como da Figura 7.

 

Caso na saída Compile Output apareça algo como "error: QtSerialPort/QtSerialport: No such file or directory" você não possui o QtSerialPort instalado ou configurado corretamente.

 

Caso você não tenha tido problemas com o Build Project ignore a etapa a seguir, Instalando o QtSerialPort, visto que apenas quem encontrar erros deve realizá-la.

 

 

Instalando o QtSerialPort

 

A única exigência é possuir Perl instalado, do mais vamos resolver nas etapas a seguir.

 

Primeiro, clone o repositório do qtserialport:

 

Como já possuímos o Qt5 instalado, agora é só compilar:

 

Caso aparecer o erro "qmake: could not exec '/usr/lib/x86_64-linux-gnu/qt4/bin/qmake': No such file or directory", pode ser que você teve outro Qt instalado, ou já instalou algo com o gerenciador de pacotes do Linux e teve que utilizar o qmake. Neste caso é só usar o mesmo caminho onde o Qt5 está instalado.

 

No meu caso está em /home/bueno/Qt/5.4/gcc_64/bin/qmake.

 

 

Em seguida termine a instalação:

 

Pronto. Você esta com o QtSerialPort instalado. Teste o projeto novamente clicando em Build Project.

 

 

Listando Portas

 

Vamos agora adicionar ao nosso main.cpp, um código que deve listar as portas seriais do computador.

 

 

No código criado acima temos a função LoadPorts(), cuja implementação é baseada no exemplo da própria Qt [4], onde utilizando QtSerialPortInfo vamos obter informações detalhadas da porta serial, como as portas disponíveis e informações como o nome da porta, fabricante e descrição. Cada porta será adicionada à variável device, que é uma StringList.

 

Voltando ao main(), nele temos outra QStringList portSerial que irá receber o retorno de LoadPorts(), e a sequência é muito simples. Verificamos o número do portSerial que será a quantidade de devices. Se for 0 nenhuma porta serial foi detectada, caso seja maior que 0 as portas são impressas na tela com os seus nomes e suas informações.

 

Clicando no botão Run ou o atalho (Ctrl + R), vamos obter uma saída como abaixo:

 

Agora conectando um dispositivo serial, no meu caso o Arduino UNO:

 

Caso mais algum dispositivo que emule através da porta USB a serial seria acrescentado índice acima.

 

 

Comunicando com o Arduino 

 

Que tal agora fazer uma comunicação de verdade? Para isso vamos contar com a ajuda do Arduino UNO, onde através da sua porta USB iremos comunicar via serial com o Qt. Caso não conheça o Arduino ou teve pouco contato pode acessar os posts do Fábio Souza, Arduino UNO [5] e Arduino - Primeiros Passos [6].

 

Segue abaixo o código-fonte do firmware do Arduino. Poderia ser uma aplicação simples, como receber e imprimir o caractere recebido ou enviá-lo de volta, mas pensei, vamos fazer algo mais legal, porque não um simples prompt? Onde recebe um comando e trata o mesmo reportado a saída ou um erro, e no nosso caso o Qt será nosso prompt.

 

Vamos começar com o código-fonte do Arduino.

 

 

O código está bem comentado para ajudar a compreensão, o foco é atender os comandos hardware, versao e help que são recebidos pela serial e imprimir estas informações na tela e tratar a comunicação como um prompt.

 

A novidade aqui é o serialEvent() [7], que antes da interação de cada loop() verifica se algum byte foi recebido, e eventualmente indica a recepção de um comando. Para compreender melhor o serialEvent() veja o artigo Entendendo e usando serialEvent() [8].

 

Agora a implementação no lado do Qt5, você pode editar o main.cpp do projeto atual ou criar outro projeto para isso e adicionar o código abaixo ao seu main.cpp. Lembrando, é claro, de editar o arquivo .pro, para criar um novo projeto.

 

 

No código acima, acho que posso ser bem breve pois em cada etapa eu adicionei um comentário. As funções de ler e escrever na porta serial usando o QtSerialPort é baseado na implementação exemplo no site do Qt [9][10], e mais detalhes sobre manipulação de IO no Qt pode ser visto na sessão QIODevice [11], recomendo este link para conhecer melhor as opções e flags que podem ser utilizadas.

 

Vamos construir nossa aplicação e executa-la. Pode clicar em Build Project (Ctrl + B), e como usei o diretório /tmp para o projeto vou acessá-lo por esse caminho. Você deverá trocar pelo caminho que escolheu. Vamos executar a aplicação:

 

Que legal, na saída dos comandos acima podemos ver que quando executei sem o Arduino conectado deu um aviso na tela da maneira correta de execução. Logo em seguida passei uma porta incorreta e foi dado o erro de que não foi possível abrir o dispositivo. Logo em seguida, com a porta correta, foi realizada a conexão e já apareceu a entrada do nosso prompt, aguardando os comandos. Note que se não passar um segundo parâmetro, que é o baudrate, é assumido por padrão 9600 bps.

 

Com os comandos corretos help, hardware e versao foram retornadas as devidas informações e os comandos inexistentes uma mensagem de exceção. Se gostou da ideia, você pode estender as funções do Qt agora, como por exemplo no que eu digitei o comando clear e não aconteceu nada, poderia fazer de limpar a tela do terminal, poderia adicionar um timeout caso depois de algum tempo nenhum comando for digitado.

 

O Qt é muito poderoso e usei neste post apenas uma pequena parcela de seu poder e também do QtSerialPort, que podemos trabalhar com conexões assíncronas e síncronas. E se você já trabalhou com termios [12] do Linux em aplicações C para comunicação serial, fique mais confortável, é em cima dele que o QtSerialPort foi escrito para manipular o device.

 

No próximo artigo, com o Qt5 vamos ver como realizar comunicação serial utilizando o QtSerialPort só que desta vez usando uma interface gráfica e o que mais podemos agregar à nossa aplicação.

 

Espero que tenham gostado, até a próxima! 

 

 

Referências

 

[1] https://www.embarcados.com.br/python-arduino-comunicacao-serial/

[2] http://cleitonbueno.com/qt5-conhecendo-um-verdadeiro-canivete-suico/

[3] http://cleitonbueno.com/qt5-instalacao-em-ambiente-linux/

[4] https://qt-project.org/wiki/QtSerialPort 

[5] https://www.embarcados.com.br/arduino-uno/

[6] https://www.embarcados.com.br/arduino-primeiros-passos/

[7] http://arduino.cc/en/Tutorial/SerialEvent

[8] http://cleitonbueno.com/arduino-entendendo-e-usando-o-serialevent/

[9] http://doc.qt.io/qt-5/qtserialport-creaderasync-example.html

[10] http://doc.qt.io/qt-5/qtserialport-cwriterasync-example.html

[11] http://doc.qt.io/qt-5/qiodevice.html

[12] http://linux.die.net/man/3/termios

Socio-proprietario da B2Open realizando consultoria, treinamentos e projetos para Sistemas Embarcados. Entusiasta a filosofia open-source, mais de 10 anos de experiências em Linux e FOSS. Foco em sistemas embarcado do firmware baremetal ao Linux Embedded, e há aproximadamente 8 anos desenvolvendo em (C, Python, Qt e muito Shell Script), além de profling, hardening e tuning para targets com Linux Embarcado. Graduado em Engenharia da Computação com ênfase em robótica e sistemas embarcados.