IoT Para Desenvolvedores C# com dotnet/iot - Embarcados
Bibliotecas .NET Core IoT
Hardware para Demonstrações – Apalis iMX8QM
System.Device.Gpio – Demonstração
Deploy – LED Blink
IoT.Device.Bindings – Demonstração
Deploy – DHT11
O .NET Core 3 foi lançado no dia 23/09/2019, com novidades para o mundo dos sistemas Embarcados e IoT. Como vimos no artigo anterior agora temos suporte a ARMv8 64 bits, onde demonstramos o deploy de um "Hello World" utilizando .NET Core e C# em uma placa com processador i.MX8QXP.
Nesse artigo vamos demonstrar a segunda novidade deste lançamento, as interfaces para acesso a GPIO do .NET Core 3, que eu tive o prazer de contribuir para o projeto open source do GitHub da .NET Foundation (fico devendo um artigo sobre os aspectos técnicos destas contribuições aqui no Embarcados).
O .NET Core pode ser usado para criar aplicativos para dispositivos IoT Linux Embarcado. É normal que aplicativos de IoT interajam com sensores, monitores e dispositivos de entrada que exigem o uso de GPIO (General Purpose Input Output), portas seriais ou hardware semelhante.
Para facilitar acesso e padronizar uma API a essas interfaces, utilizando .NET Core, que foi criado o projeto dotnet/iot, dentro do grupo da .NET Foundation que dá suporte ao projeto open source do .NET Core. Esse projeto implementa a System.Device.Gpio library que tem as interfaces para acesso a GPIO, PWM, I2C e SPI.
A comunidade do projeto dotnet/iot ainda foi além e desenvolveu também a biblioteca IoT.Device.Bindings, que utiliza a API do System.Device.Gpio para fornecer abstrações, drivers, e classes prontas para controle de sensores e dispositivos populares.
No artigo anterior eu utilizei um Toradex Colibri iMX8QXP ARMv8 64 bits quad core 4x Cortex-A35. Neste artigo eu estou com um monstro mais poderoso ainda: o Apalis iMX8QM, que foi lançado oficialmente pela Toradex nesta última terça feira 08/10/2019. Um ARMv8 64 bits HEXA core com 2x Cortex-A75, 4x Cortex-A53, 4 GB de RAM (SIM eu falei 4 GB RAM) e 16 GB eMMC.
A Toradex foi uma das seletas parceiras da NXP com acesso antecipado ao i.MX8QM para desenvolvimento do System on Module Apalis iMX8QM e do ecossistema de software, junto a seus parceiros e clientes. Estou com um monstro desses em mãos, para testes, e foi ele que utilizei nas demonstrações deste artigo.
Qual a melhor forma de exemplificar a utilização de uma API de GPIO? Ahh, o bom e velho LED blink, o Hello World dos sistemas embarcados.
Vamos primeiramente criar, em um computador de desenvolvimento, nosso projeto com o comando:
Lembrando que estamos utilizando o novo .NET Core 3. No comando acima o .NET SDK vai criar nosso projeto com o nome da pasta de onde executamos o comando. No meu caso minha pasta tem o nome demo2, logo meu projeto vai ser configurado com o nome demo2.
Para utilizar a biblioteca System.Device.Gpio temos que adicionar seu pacote NuGet ao projeto. Execute o seguinte comando para adicionar o pacote NuGet do dotnet/iot:
dotnet add package System.Device.Gpio --version 1.0.0 dotnet restore
dotnet add package System.Device.Gpio --version 1.0.0
Agora podemos, enfim, escrever o código C# do Blink:
using System; using System.Threading; using System.Device.Gpio; namespace demo2 { class Program { static void Main(string[] args) { // GpioController set bank 0 as default GpioController controller = new GpioController(); // GPIO bank 0 line 12 int GPIO0_IO12 = 12; // say hello Console.WriteLine("Blinking on Apalis iMX8QM with .NET Core 3"); // set pin mode to output controller.OpenPin(GPIO0_IO12, PinMode.Output); // blink forever while(true) { Console.WriteLine("Blink"); controller.Write(GPIO0_IO12, PinValue.High); Thread.Sleep(500); controller.Write(GPIO0_IO12, PinValue.Low); Thread.Sleep(500); } } } }
// GpioController set bank 0 as default
// GPIO bank 0 line 12
int GPIO0_IO12 = 12;
Console.WriteLine("Blinking on Apalis iMX8QM with .NET Core 3");
controller.OpenPin(GPIO0_IO12, PinMode.Output);
Console.WriteLine("Blink");
controller.Write(GPIO0_IO12, PinValue.High);
controller.Write(GPIO0_IO12, PinValue.Low);
Note a linha 14, onde estamos construindo um objeto GpioController que terá os comandos de interface para controlar nossos pinos de entrada e saída. Na linha 20 usamos o método OpenPin para configurar nosso pino, onde teremos conectado um LED, para output, esse método é muito importante pois todos os outros métodos do controller só serão executados em um pino anteriormente configurado. E por fim nas linhas 25 e 27, dentro da nossa estrutura de repetição, utilizamos o método Write que vai setar o nível lógico do pino que foi configurado como output.
Para realizar o deploy para a arquitetura do nosso sistema embarcado vou utilizar o mesmo comando do artigo passado, mas com um adendo:
dotnet publish -r linux-arm64 --self-contained true /p:PublishSingleFile=true
Outra novidade do .NET Core 3 é que agora temos a opção de publicar um projeto como sendo um único arquivo executável, que é a função desse último argumento /p:PublishSingleFile=true. Agora ao invés de ser gerada uma pasta /publish com todas as dependências, vários .dll e .so, teremos apenas dois arquivos:
Assim, copiando apenas esse executável gerado, já teremos todo nosso projeto pronto para ser executado no nosso sistema embarcado:
scp bin/Debug/netcoreapp3.0/linux-arm64/publish/demo2 torizon@10.42.0.22:/home/torizon
Acessando o bash da placa, via ssh, podemos então executar o programa .NET Core 3 IoT:
Lembrando que no caso de acesso ao hardware, GPIO nesse caso, precisamos executar com privilégios de super usuário. Nesse momento, se tudo deu certo, teremos um LED piscando conectado à porta GPIO0_IO12 do nosso Apalis iMX8QM.
Para demonstração das bibliotecas do IoT.Devices.Bindings vou utilizar um sensor de temperatura muito popular: o onipresente DHT11.
Para utilizar o IoT.Devices.Bindings em nosso projeto temos que primeiramente adicionar o pacote NuGet:
dotnet add package Iot.Device.Bindings --version 1.0.0
O DHT11 já tem uma implementação pronta para uso, então podemos utilizar o sensor facilmente:
using System; using System.Threading; using Iot.Device.DHTxx; using Iot.Units; namespace demo3 { class Program { static void Main(string[] args) { // GPIO bank 0 line 12 int GPIO0_IO12 = 12; // say hello Console.WriteLine("DHT11 on Apalis iMX8QM with .NET Core 3"); // use the Dht11 class using (Dht11 sensor = new Dht11(GPIO0_IO12)) { while (true) { // easy device controll Temperature temp = sensor.Temperature; double humidity = sensor.Humidity; if (sensor.IsLastReadSuccessful) { Console.WriteLine($"Temperature :: {temp.Celsius}"); Console.WriteLine($"Humidity :: {humidity}"); Console.WriteLine("----------------------------------"); } // wait 1 second to the next read Thread.Sleep(1000); } } } } }
using Iot.Device.DHTxx;
using Iot.Units;
Console.WriteLine("DHT11 on Apalis iMX8QM with .NET Core 3");
// use the Dht11 class
using (Dht11 sensor = new Dht11(GPIO0_IO12))
// easy device controll
Temperature temp = sensor.Temperature;
if (sensor.IsLastReadSuccessful)
Console.WriteLine($"Temperature :: {temp.Celsius}");
Console.WriteLine($"Humidity :: {humidity}");
// wait 1 second to the next read
Note como simplesmente instanciamos um objeto do tipo Dht11, linha 19, referenciando o pino de dados conectado à placa e ao sensor e pronto. Podemos então requisitar a temperatura, linha 24, e a umidade do sensor, linha 25. O objeto vai realizar as chamadas e controles necessários, por debaixo dos panos utilizando as APIs do System.Device.Gpio, para entregar esses dados de forma fácil.
Executando os mesmos comandos do deploy da demonstração do LED Blink dentro da pasta do projeto:
Copiando o executável único gerado via ssh:
scp bin/Debug/netcoreapp3.0/linux-arm64/publish/demo3 torizon@10.42.0.22:/home/torizon
E pronto, teremos as leituras do DHT11 sendo apresentadas no bash da placa:
Confira o vídeo onde demonstro a utilização e programação descritas nesse artigo na prática:
Legal como o System.Device.Gpio tem uma API bem simples, algo bem parecido com as chamadas do Arduino por exemplo, para você programar dispositivos com linguagem C# e o .NET Core 3.0.
As implementações do IoT.Device.Bindings facilitam e agilizam muito o desenvolvimento de aplicações IoT, com uma extensa lista de dispositivos e sensores disponíveis. Você pode acompanhar todos dispositivos no Github do projeto: https://github.com/dotnet/iot/tree/master/src/devices
Lembrando que o .NET Core e o .NET IoT são projetos da Microsoft totalmente open source. Ou seja, como eu contribuí, você também pode contribuir! A comunidade é um grande adjuvante na inclusão e suporte de vários dispositivos para o projeto.