Desenvolvimento de aplicação com interface gráfica (em Qt/QML) e comunicação CAN para controle de motor elétrico utilizando C++ e TorizonCore

Este artigo explora o fluxo de desenvolvimento de uma aplicação com interface gráfica, que comunica-se, via protocolo CAN, com um controlador de um motor elétrico.

Este artigo explora o fluxo de desenvolvimento de uma aplicação com interface gráfica, que comunica-se, via protocolo CAN, com um controlador de um motor elétrico. Para isso, vamos utilizar um módulo Colibri IMX7D da Toradex, o sistema operacional TorizonCore, a linguagem de programação C++ e a linguagem QML, do framework Qt, para a interface gráfica.

O protocolo de comunicação CAN (Controller Area Network) e os protocolos baseados nele são comumente utilizados em alguns ramos da indústria como, por exemplo, Agronegócio (SAE J1939), IoT (Internet of Things), Automação Industrial (CANopen, DeviceNet), Automotivo (FlexRay), Aviação (ARINC-825), entre outros.

Aqui, veremos como podemos desenvolver uma aplicação do zero, para estabelecer comunicação utilizando o CANopen.

Nossa configuração é apresentada na Figura 1: o módulo Colibri IMX7D é conectado com o computador de desenvolvimento via cabo Ethernet e também é conectado ao dispositivo CAN (controlador do motor) via um cabo CAN. No computador de desenvolvimento, temos instalado Ubuntu 20.04, Visual Studio Code (apelidado de VS Code) com o VS Code Extension for Torizon e também temos o Docker instalado. No módulo, temos a versão trimestral (Quarterly) mais recente do TorizonCore: a versão 5.1.0.


image 20
Figura 1: Ambiente de desenvolvimento

TorizonCore é a Distribuição Linux da Toradex para sistemas embarcados. Ela é gratuita e de fácil utilização. Embora você possa optar por criar sua própria Distribuição Linux específica e única para seu projeto utilizando ferramentas como o Yocto ou o Buildroot, o TorizonCore coloca a aplicação no foco central do desenvolvimento. Seu tempo de desenvolvimento é investido mais diretamente na geração de valor, ao invés de outra tarefas como a construção de uma Distribuição Linux customizada. Se você desenvolve sua própria Distribuição, você precisa checar por dependências entre receitas e pacotes e/ou re-compilá-la diversas vezes por várias horas caso haja necessidade de resolver erros de compilação durante o processo. Com TorizonCore, isto é feito de maneira mais simples: tais modificações são realizadas na imagem Docker de sua aplicação. Veja uma comparação de caracterísiticas entre ambos: https://www.toradex.com/operating-systems#embedded-linux

Além disso, outras ferramentas do Ecossistema Torizon como o TorizonCore Builder e o VS Code Extension for Torizon simplificam o processo de desenvolvimento tanto para a customização do TorizonCore quanto para a aplicação e seu contêiner.

Na Tabela 1 estabelecemos uma comparação entre a utilização do Yocto e a utilização do Ecossistema Torizon – que acompanha a Distribuição TorizonCore – para o desenvolvimento de um projeto de sistema embarcado. Na coluna central temos a Tarefa de desenvolvimento a ser realizada e, nas colunas da esquerda e da direita, temos o Ecossistema Torizon e o Yocto ,respectivamente, com a descrição de como seria realizada a tarefa relacionada.

Ecossistema Torizon Tarefa Yocto
Instalar do VS Code Extension for Torizon Configurar do ambiente de desenvolvimento Clonar a Toradex Reference Image para Yocto Project
Listar os pacotes na extensão do Torizon Organizar as dependências e/ou requerimentos da aplicação Encontrar as receitas que contém os pacotes necessários
Habilitar dispositivos aplicando device tree overlays com o TorizonCore Builder Habilitar dispositivos Habilitar dispositivos utilizando menu_config
Adicionar device drivers out of tree diretamente de seus repositórios utilizando TorizonCore Builder Adicionar device drivers out of tree criando ou reutilizando receitas para tal
Não é necessário “Pré-configurar” a Distribuição Linux Checagem cruzada das versões dos pacotes e receitas até encontrar uma combinação adequada
Não é necessário Compilar a cross-toolchain e o SO Compilação do SO e de sua cross-toolchain
Configurar a imagem de Docker no VS Code Extenion for Torizon “Pós-configurar” a Distribuição Linux Instalar o SO e configurá-lo
Não é necessário Configurar uma IDE para utilizar as ferramentas de desenvolvimento Configurar uma IDE para cross-compilação e depuração. Se possível, depuração remota
Desenvolvimento da aplicação a partir de modelos pré-configurados (C/C++, Python, C#) Início do desenvolvimento da aplicação Desenvolvimento da aplicação
Depuração remota no módulo diretamente do VS Code Depuração da aplicação Depuração da aplicação (depende de sua configuração e ferramentas que estão sendo utilizadas)
Utilizar TorizonCore Builder para criar facilmente uma imagem instalável pelo Toradex Easy Installer Preparação da aplicação e do SO para implantação e distribuição Criar uma imagem com a aplicação  integrada
Criar uma imagem instalável pelo Toradex Easy Installer
Instalar a imagem utilizando o Toradex Easy Installer Distribuir a aplicação e o SO no produto final Instalar a imagem utilizando o Toradex Easy Installer
Enviar a imagem do SO e a(s) imagem(ns) de Docker para o Torizon OTA (Over The Air update) utilizando o TorionCore Builder
Utilizar o Torizon OTA Atualizar a aplicação Estratégia deve ser desenvolvida e implementada
Atualizar o Sistema Operacional Estratégia deve ser desenvolvida e implementada

Agora falaremos um pouco sobre a comunicação CAN, que será utilizada na aplicação exemplo.

Para a comunicação CAN, vamos utilizar o protocolo CANopen. Nosso objetivo não é implementar nem utilizar todo o stack CANopen e seus modos de comunicação, mas fazer o mínimo necessário para termos uma aplicação funcionando. Vamos utilizar o modo Network Management (mensagens MNT), modo Server-Client (mensagens SDO) e modo Real-Time messaging (mensagens PDO). Se você tiver interesse, você pode utilizar bibliotecas que implementam todo o stack CANopen, como a Lely-Core (https://opensource.lely.com/canopen/), CANopenNode (https://github.com/CANopenNode/CANopenNode), OpenCANopen (https://github.com/marel-keytech/openCANopen),e CanFestival (https://canfestival.org), por exemplo..

Do ponto de vista de comunicação, mensagens Network Management (NMT) são utilizadas para definir um estado NMT para os dispositivos escravos: Pre-Operational, Operational ou Stopped (Booting Up também é um estado possível, mas apenas ocorre quando o dispositivo está ligando). Vamos utilizar mensagens NMT para colocar o dispositivo no estado Pre-Operational, configurá-lo e então colocá-lo no estado Operational. Também utilizaremos para reiniciar o controlador do motor, caso necessário.

Mensagens Service Data Object (SDO), utilizadas no estado Pre-Operational (preferencialmente), ou no estado Operational, são utilizadas principalmente para para configurar o dispositivo e para realizar leitura de suas propriedades, dado que é possível acessar qualquer item de seu Dicionário de Objetos. Por outro lado, uma mensagem SDO pode carregar, no máximo, apenas um valor do Dicionário de Objetos. Também é possível “fatiar” um valor do Dicionário de Objetos em várias mensagens SDO, mas não exploraremos essa possibilidade. Vamos utilizar essas mensagens para configurar as propriedades das mensagens PDO e definir os modos de operação do motor (modo de velocidade ou de posição).

Process Data Object (PDO) são mensagens trocadas entre os dispositivos quando em estado Operational. Essas mensagens têm propriedades configuráveis e podem carregar até oito itens do Dicionário de Objetos, a depender do tamanho (em bytes) dos objetos. Vamos utilizar mensagens PDO para ler a velocidade e/ou a posição do motor.

Você pode ler mais sobre CAN no artigo CAN Bus da Wikipedia (https://en.wikipedia.org/wiki/CAN_bus) e sobre CANopen no artigo CANopen Explained – A Simple Intro da CSSEltronics (https://www.csselectronics.com/screen/page/canopen-tutorial-simple-intro).

Para realizar a comunicação CAN, utilizaremos o socketCAN (https://en.wikipedia.org/wiki/SocketCAN) e system calls comumente utilizadas para isso como read, write e select.

PPara começarmos, precisamos do Docker e do VS Code instalado, e também do VS Code Extension for Torizon (https://developer.toradex.com/knowledge-base/visual-studio-code-extension-for-torizon).. Na Figura 2, vemos que estão instalados no VS Code tanto a versão de acesso antecipado quanto o suporte ao QtDesignStudio para projetos Torizon.

image 8
Figura 2: Instalando o VS Code Extension for Torizon

Depois disso, precisamos fazer com que a extensão reconheça nosso módulo (https://developer.toradex.com/knowledge-base/visual-studio-code-extension-for-torizon#Add_Target_Device_Connection_In_Visual_Studio_Code). Na Figura 3 vemos tanto algumas configurações do projeto (que precisamos modificar) quanto o módulo Colibri IMX7D reconhecido pelo VS Code Extension for Torizon por meio de uma conexão de rede com o computador de desenvolvimento.

image 9
Figura 3: VS Code Extension for Torizon instalado no VS Code

Então, criaremos um novo projeto C++ com Qt/QML para nosso módulo, baseado no modelo disponibilizado pela extensão (https://developer.toradex.com/knowledge-base/qt-c-application-development-using-visual-studio-code-and-torizon). Basta pressionar F1 e começar a digitar o comando >Torizon/C-C++: Create C/C++ application que o VS Code nos ajudará a encontrá-lo, como podemos ver na Figura 4. Em seguida, precisamos definir um nome para o projeto (Figura 5) e em qual pasta ele será criado. Após, selecionamos Qt QML sample como modelo de projeto que utilizaremos (Figura 6).

image 18
Figura 4: Criando projeto C++ com suporte a Qt/QML a partir de modelo pré-configurado

image 10
Figura 5: definindo nome para o projeto

image 11
Figura 6: Modelos de projetos

Depois de configurar o projeto baseado no modelo disponível, o VS Code Extension for Torizon começará a fazer o download e configuração do Software Development Kit (SDK) necessário para compilar, enviar para o módulo e depurar uma aplicação HelloWorld C++ com Qt/QML em um contêiner. Isto acontece com todos os módulos que suportam o TorizonCore. Toda configuração inicial necessária é realizada automagicamente pelo VS Code Extension for Torizon.

Depois do download e configuração, podemos explorar o que podemos fazer com nossa IDE.

Por exemplo, faça o teste de digitar engine no arquivo cpp de seu projeto. Você verá que o VS Code tenta ajudar-nos a auto-completar o que estamos digitando (Figura 7), baseado nos pacotes baixados pela extensão e nas variáveis acessíveis pelo a partir do escopo atual. Você também pode requisitar dicas pressionando CTRL + Barra de Espaço.

image 12
Figura 7: Auto-completar no VS Code

Se você fizer um CTRL + Clique esquerdo do mouse sobre uma variável, função, cabeçalho, etc, o VS Code irá levá-lo até a definição daquele identificador clicado ou, apenas colocando o mouse sobre o símbolo e segurando CTRL, vemos algumas informações sobre este (Figura 8).

image 13
Figura 8: Informações exibidas ao colocar o mouse sobre um símbolo e segurar CTRL.

Antes de enviarmos nossa aplicação HelloWorld para o módulo, vamos definir um ponto de parada (breakpoint) nela. Podemos fazer isso clicando à esquerda do número da linha do código. Vamos colocar um ponto de parada na linha 19 (Figura 9).

image 14
Figura 9: Ponto de parada (breakpoint) definido na linha 19

Agora, pressionando F5, você verá a mágica acontecendo: a extensão irá compilar e integrar nossa aplicação em um contêiner e então enviá-la para o módulo. Você pode ver os passos realizados no Output Window. Na primeira vez, este passo é um pouco demorado (e também depende da velocidade de sua internet) pois a extensão vai fazer o download de vários pacotes durante a compilação da imagem Docker para o contêiner de sua aplicação. Na próxima vez que você apertar F5, o processo será mais rápido.

Após o envio para o módulo, a aplicação HelloWorld estará sendo executada no módulo e você verá que o VS Code estará parado na linha 6 de seu código (por padrão, é definido um ponto de parada no início da aplicação), aguardando por algum comando para continuar a execução ou cessá-la.

image 19
Figura 10: Execução da aplicação pausada na linha 6.

Continuando a execução (pressionando F5 ou clicando no pequeno botão play azul, no topo da Figura 10), a depuração continuará até atingir a linha 19 e pausar novamente, que foi o lugar onde definimos nosso ponto de parada. Neste ponto de parada, colocando o mouse sobre as variáveis do programa, o VS Code nos mostra seu valor, assim como todos esse valores podem ser vistos na aba Run, juntamente com as variáveis observadas (watched variables), a pilha de chamada de funções (call stack) e seus pontos de parada (breakpoints) (Figura 11).

image 16
Figura 11: Aplicação sendo executada no módulo e sendo depurada no VS Code

Continuando a execução novamente, vamos ver que uma janela completamente branca, que é justamente nossa aplicação HelloWorld, vai ser exibida no display do nosso módulo (Figura 12).

image 17
Figura 12: Aplicação padrão aparecendo no display do módulo.

Após obtermos nosso resultado – a janela branca -, podemos fechá-la parando a aplicação pelo VS Code. Agora vamos começar a fazer alterações no projeto para executarmos a aplicação que é o objetivo deste artigo.

Para habilitar a comunicação CAN, precisamos:

  • Utilizar TorizonCore Builder:
  • No VS Code Extension for Torizon (https://developer.toradex.com/knowledge-base/how-to-use-can-on-torizoncore)
    • Capacidade de Administração de Rede (NET_ADMIN), para que o contêiner de nossa aplicação tenha capacidade de gerenciar interfaces de rede;
    • Adicionar os pacotes iproute2 e can-utils na imagem de nossa aplicação para podermos gerenciar a interface CAN (habilitar, desabilitar e configurar) e também testá-la;
    • Definir o modo de rede (Network Mode) como host, para que possamos trocar mensagens CAN com o mundo externo
    • Definir root como usuário 
  • Embora fazer isto não seja uma prática indicada, para este tutorial fazemos isso para poder configurar nossa interface CAN. 
    • Uma alternativa a utilizar o usuário root na aplicação seria ter um contêiner extra, responsável por fazer as configurações necessárias, para então a aplicação não precisar ser executada pelo usuário root em seu contêiner.

Depois de realizar esses passos, você pode acessar os arquivos da aplicação deste repositório (https://github.com/griloHBG/torizon-qt-can-sample) e copiar/substituir em seu projeto. Então, após realizar as configurações colocar os arquivos em seus lugares, podemos pressionar F5 novamente para recriar o contêiner de nossa aplicação e enviar para o módulo.

Vídeo da aplicação em execução:

Agora temos um exemplo funcional de uma aplicação para sistema embarcado com interface gráfica e comunicação CANopen para controle de um motor elétrico utilizando o Ecossistema Torizon que, no fim, não é tão complexa utilizando-se as ferramentas corretas 😉 

Se precisarmos adicionar/remover/modificar qualquer pacote/dispositivo/permissão em nossa aplicação, podemos utilizar tanto o VS Code Extension for Torizon quanto o TorizonCore Builder para essas tarefas.

Você pode encontrar mais detalhes e exemplos de tarefas mais específicas na Documentação do Ecossistema Torizon (https://developer.toradex.com/software/torizon).

Notificações
Notificar
guest
1 Comentário
recentes
antigos mais votados
Inline Feedbacks
View all comments
Felipe
Felipe
24/07/2021 00:00

Excelente artigo!

WEBINAR

Imagens de Ultrassom: Princípios e Aplicações

DATA: 26/10 ÀS 19:30 H