Tutorial

O problema

Imagine-se que se pretende controlar o estado dum LED ou detectar o estado dum botão a partir dum sistema computacional como um PC, tablet ou smartphone. Embora estes equipamentos sejam bastante poderosos, dificilmente cumpririam essa missão. Pelo contrário a sua interligação com periféricos mais sofisticados como por exemplo uma webcam ou impressora não apresentaria grande dificuldade.

hand-shake

O que torna então um LED e um botão, dispositivos tão difíceis de serem interligados aos modernos sistemas computacionais?

É que dada a sua simplicidade estes dispositivos não possuem qualquer interface standard presente nos modernos sistemas computacionais, como uma porta USB ou Ethernet, e muito menos ligações sem fios como o WiFi ou Bluetooth! Com efeito o controlo dum LED faz-se através dum simples sinal elétrico digital cujo valor lógico define se o LED acenderá ou não. No caso do botão, algo de semelhante acontecerá embora desta vez seja o estado do botão (e o circuito em que ele se encontra) a definir o valor lógico do sinal digital.

Esta necessidade de ligar dispositivos simples (coisas) em rede vai na linha do que atualmente se designa por IoT – Internet of Things (Internet das Coisas)! Em lugar do LED e do botão usados neste tutorial poderíamos ter um eletrodoméstico, um sensor, etc.

A solução

Uma forma de contornar este problema é o uso de placas de desenvolvimento baseadas em microprocessadores que por um lado possuem as interfaces standard (e que por isso podem ser ligados aos sistemas computacionais) mas possuem igualmente uma interface de sinais genéricos de entrada/saída designada por isso de: GPIO – General Purpose Input/Output. Será por sua vez neste último interface, que o LED e o botão serão ligados. Nestas placas será depois necessário desenvolver um programa que faça a interligação com os interfaces anteriormente descritos.

RPi_B+

Um exemplos dessas placas é a placa Raspberry Pi, e mais concretamente o seu modelo Raspberry Pi B+ que iremos aqui estudar.

De facto, de entre as 12 placas, apenas 5 são da versão Raspberry Pi B+ enquanto que as restantes 7 são da versão Raspberry Pi 2. Atualmente existem outras versões como por exemplo a Raspberry Pi 3 e a Raspberry Pi Zero W.

As placas Raspberry Pi correm os programas em cima dum sistema operativo baseado em Linux (o Raspbian) existente no seu cartão de memória. Se por um lado esta opção beneficia das funcionalidades facultadas pelo sistema operativo, esses programas podem padecer de alguma latência temporal devido às características de multiprocessamento do sistema operativo.

Estão à disposição um grande conjunto de linguagens para o desenvolvimento de aplicações para as placas Raspberry Pi, embora neste tutorial seja usada simplesmente a linguagem Python.

Em termos de interfaces com os sistemas computacionais, as placas Raspberry Pi possuem uma porta Ethernet, o que não invalida que outro tipos de ligações possam ser feitas, nomeadamente sem fios através de módulos/dongles a ligar aos seus portos USB.

Este tipo de placas tem um custo relativamente baixo embora exijam um conjunto adicional de acessórios como é o caso duma fonte de alimentação e o cartão de memória onde residirá o sistema operativo.

Tutorial

Neste tutorial será mostrado como é que com o recurso a estas placas se pode controlar um LED (i.e. ligá-lo e desligá-lo) e saber o estado dum botão (i.e. se está ou não premido).

Para isso serão trocadas mensagens MQTT entre o dispositivo computacional e a placa. Essas mensagens são geridas por um software (de nome Mosquitto) e que neste caso foi também instalado no Raspberry Pi. O nosso programa fará a publicação de mensagens MQTT (com o estado do botão) e subscreverá outras (as do estado pretendido para o LED), em ambos os casos perante o software Mosquitto que desempenhará o papel de Broker.

As mensagens MQTT são constituídas basicamente por dois campos: o tópico e a mensagem propriamente dita. Neste exemplo temos as seguintes duas mensagens:

Objetivo Tipo Topic Message
Informar do estado do Botão publish but on v off
Comando a receber para (des)ligar o LED subscrive led on v off

Raspberry Pi

O uso destas placas pressupõe a prévia instalação no cartão de memória do sistema operativo bem como a realização dum conjunto de configurações iniciais descritas aqui.

Embora estas placas possam ser ligadas a um monitor pelo porto HDMI, e a um teclado e/ou rato pelas suas portas USB, iremos fazer uma utilização remota através duma ligação SSH utilizando de novo a aplicação PuTTY. Esta forma de utilização é por isso conhecida de “headless“.

Para isso basta abrir a sessão SSH configurada pelo procedimento descrito aqui.

Programa de teste “Hello World”

Ao estabelecermos uma ligação SSH, a linha de comandos inicia-se na pasta home do utilizador pi, podendo ver-se o seu conteúdo através do comando:

ls

Sugere-se a criação duma pasta para esta unidade curricular através do comando:

mkdir edm

Por fim e para se criar um primeiro programa Python hello.py, bastará fazer:

cd ~/edm
nano hello.py

Nesse programa iremos simplesmente escrever:

print("Hello World!")

Saindo através do atalho Ctrl+x seguido de y+enter (para guardar o ficheiro).

Este programa pode depois ser executado fazendo:

python hello.py

Programa raspi

No caso do programa de ligação com o LED e o botão o procedimento é semelhante:

cd ~/edm
nano raspi.py

Desta vez o código python é o seguinte:

import paho.mqtt.client as mqtt
import platform
import pigpio

# Editar o IP em funcao da bancada XX
RPi = "10.0.0.1XX"
Broker = "10.0.0.1XX"

if platform.uname()[4][0:3] == "arm":
    pi = pigpio.pi()
else:
    pi = pigpio.pi(RPi)

def onBi(gpio, level, tick):
    if level == 0:
        print("but on")
        client.publish("but", "on")
    else:
        print("but off")
        client.publish("but", "off")

Bi = 17
pi.set_mode(Bi, pigpio.INPUT)
pi.callback(Bi, pigpio.EITHER_EDGE, onBi)

Lr = 4
pi.set_mode(Lr, pigpio.OUTPUT)

def on_connect(client, userdata, flags, rc):
    print("Connected with result code "+str(rc))
    client.subscribe("led")

def on_message(client, userdata, msg):
    print(msg.topic + " " + str(msg.payload))
    if msg.topic == "led":
        if msg.payload == "on":
            pi.write(Lr, 1)
        if msg.payload == "off":
            pi.write(Lr, 0)

client = mqtt.Client()
client.on_connect = on_connect
client.on_message = on_message
client.connect(Broker, 1883, 60)

client.loop_forever()

Ainda antes de executar o programa é necessário efetuar as ligações do LED e do botão com determinados pinos do interface GPIO da forma como o seguinte esquemático Fritzing ilustra:

Raspberry_ledbut_bb

IMPORTANTE: As ligações na breadboard deverão ser realizadas com o máximo cuidado pois alguma troca poderá danificar a placa Raspberry Pi. Esteja nomeadamente atento ao LED vermelho da placa Raspberry Pi que caso apague indicia a existência dum curto circuito!

Para facilitar as ligações iremos já usar um módulo que contém 3 LEDs e 2 botões ligados da seguinte forma:

butled_edm

modulo

Para correr o programa bastará agora executar o comando:

python ~/edm/raspi.py

Após a execução do programa ele fica a aguardar a troca de mensagens MQTT, podendo o processo ser interrompido a qualquer momento clicando em ctrl+c.

Teste do programa raspi

Para se testar o programa bastará agora publicar/subscrever as anteriormente referidas mensagens MQTT, algo que será feito com recurso a um software instalado nos PCs chamado MQTT.fx e cujo atalho está dentro da pasta EDM presente no ambiente de trabalho. O processo de instalação deste “MQTT client” pode ser visto aqui.

O primeiro passo consiste em criar uma ligação ao nosso Broker, carregando para isso na roda dentada do interface do programa. Aí deveremos criar um novo “connection profile” (+), definindo depois o respetivo “profile name” (por exemplo RPi) e “broker address” (10.0.0.1XX).

Depois a publicação das mensagens para controlo do estado do LED fazem-se carregando no botão Publish, definindo o tópico na dropdown box à esquerda do botão Publish (led neste caso), e a respetiva mensagem no campo imediatamente abaixo (on ou off consoante se queira ligar os desligar o LED).

No caso da subscrição das mensagens com o estado do botão, teremos que carregar no botão Subscrive e aí definir o tópico pretendido (but neste caso).

Reboot e Shutdown

Sempre que fôr necessário rearrancar o sistema usar o comando:
sudo reboot

Para desligar por completo, usar o comando:
sudo shutdown -h now

Neste caso só se deve desligar a alimentação da placa quando o LED verde (que indica o acesso ao cartão) após alguma atividade apaga por completo ficando apenas o LED vermelho ligado. De outro modo corremos o risco de corromper o conteúdo do cartão impedindo a placa de voltar a arrancar.

Para rearrancar o sistema após um shutdown, é necessário desligar e ligar novamente a alimentação!

Eclipse

Ao contrário do programa hello.py, o programa de controlo do LED e botão apresenta uma maior complexidade pelo que não é adequado ser visto/editado com o editor nano.

Em alternativa iremos usar um ambiente integrado de desenvolvimento (IDE) designado por Eclipse que está já acessível na pasta C:/Alunos/EDM do Windows presente nos PCs das bancadas. O processo de instalação deste ambiente pode ser visto aqui.

Embora esse IDE esteja situado nos PCs e não nas placas, ele pode editar remotamente os módulos Python que compõem o programa. Isso é possível graças ao plugin RSE (Remote System Explorer) juntamente com o plugin PyDev. É contudo primeiro necessário:

  • Abrir essa perspetiva: Window > Perspective > Open Perspective > Other… > Remote System Explorer
  • Criar uma nova ligação: Remote Systems < New > Connection… > SSH Only > Next
    • Hostname: 10.0.0.1XX (o IP da placa)
    • Connection name: RPi
    • Finish
  • Abrir a pasta edm no Raspberry Pi: Remote Systems < RPi > Sftp Files > My Home > edm
    • User ID: pi
    • Password: a palavra-passe fornecida na aula
    • Activar “Save user ID” e “Save Password” para não ser necessário repetir o processo numa próxima vez
    • OK 
  • É natural que no primeiro acesso seja:
    • apresentado um aviso (Warning) relativo à autenticidade a que devemos dizer Yes
    • pedida a indicação dum “Password hint“, que podemos ignorar respondendo No.

Torna-se assim possível ver/editar de uma forma mais amigável o módulo que compõe este programa.

Node-RED

Uma forma alternativa de interagir com o nosso programa raspi é via um interface Web facultado pelo programa Node-RED, sendo o acesso feito por isso através dum browser no seguinte endereço: http://10.0.0.1XX:1880 (ou seja o IP do nosso Raspberry Pi e a porta 1880).

Aí é possível criar um fluxo de dados duma forma gráfica interligando um conjunto de “nodes” a dispor nessa aplicação. Uma forma rápida de criar um “Flow” é fazer um Import através do botão do canto superior direito, e copiando para o Clipboard o seguinte:

[{"id":"99d45ae7.93e0f8","type":"mqtt in","z":"811eb919.da8ae8","name":"","topic":"but","qos":"2","broker":"a657addf.de255","x":303,"y":276,"wires":[["e347c646.fef4e8","e36260c3.6795f"]]},{"id":"e347c646.fef4e8","type":"debug","z":"811eb919.da8ae8","name":"","active":true,"console":"false","complete":"false","x":530.9999084472656,"y":227.3333740234375,"wires":[]},{"id":"cddfbcee.1c3be","type":"mqtt out","z":"811eb919.da8ae8","name":"led","topic":"led","qos":"","retain":"","broker":"f4c0a900.6cab28","x":882.9999694824219,"y":361.33338928222656,"wires":[]},{"id":"a2816354.c49a4","type":"inject","z":"811eb919.da8ae8","name":"","topic":"","payload":"on","payloadType":"str","repeat":"","crontab":"","once":false,"x":736.9999084472656,"y":244.66673278808594,"wires":[["cddfbcee.1c3be"]]},{"id":"26fa6c64.36a264","type":"inject","z":"811eb919.da8ae8","name":"","topic":"","payload":"off","payloadType":"str","repeat":"","crontab":"","once":false,"x":674.4999084472656,"y":292.00001525878906,"wires":[["cddfbcee.1c3be"]]},{"id":"e36260c3.6795f","type":"ui_text","z":"811eb919.da8ae8","group":"450694f9.66f2dc","order":0,"width":0,"height":0,"name":"","label":"Botão","format":"{{msg.payload}}","layout":"row-center","x":510.9999694824219,"y":415.33338928222656,"wires":[]},{"id":"978ed7ca.86e6e8","type":"ui_switch","z":"811eb919.da8ae8","name":"","label":"LED","group":"450694f9.66f2dc","order":0,"width":0,"height":0,"passthru":true,"decouple":"false","topic":"","style":"","onvalue":"on","onvalueType":"str","onicon":"","oncolor":"","offvalue":"off","offvalueType":"str","officon":"","offcolor":"","x":656.9999084472656,"y":415.33338928222656,"wires":[["cddfbcee.1c3be"]]},{"id":"a657addf.de255","type":"mqtt-broker","z":"","broker":"10.0.0.100","port":"1883","clientid":"","usetls":false,"compatmode":true,"keepalive":"60","cleansession":true,"willTopic":"","willQos":"0","willPayload":"","birthTopic":"","birthQos":"0","birthPayload":""},{"id":"f4c0a900.6cab28","type":"mqtt-broker","z":"","broker":"10.0.0.100","port":"1883","clientid":"","usetls":false,"compatmode":true,"keepalive":"60","cleansession":true,"willTopic":"","willQos":"0","willPayload":"","birthTopic":"","birthQos":"0","birthPayload":""},{"id":"450694f9.66f2dc","type":"ui_group","z":"","name":"raspi","tab":"d30438f1.e5cc88","disp":true,"width":"6"},{"id":"d30438f1.e5cc88","type":"ui_tab","z":"","name":"EDM 2017/8","icon":"dashboard"}]

Depois de corrigir o endereço do broker nos “nodes” das mensagens MQTT (a violeta) para o valor adequado (10.0.0.1XX), é possível descarregar o “Flow” para o Raspberry Pi clicando no botão Deploy.

É ainda possível aceder ao interface gráfico acedendo ao endereço: http://10.0.0.1XX:1880/ui

Últimas considerações

1. Outros sistemas operativos

Embora todo o software de desenvolvimento usado neste tutorial tenha corrido em Windows, o software Eclipse e respetivos plugins existem igualmente para Linux e OS X.

A aplicação MQTT.fx (o MQTT client que permite gerar/visualizar mensagens MQTT associadas a um determinado Broker) existe também em Linux e OSX (como se pode comprovar aqui para o caso da versão 1.3.1). Mesmo para o caso dos sistemas operativos usados nos dispositivos móveis (como os smartphones e/ou tablets), é possível encontrar alternativas:

2. Outros dispositivos a controlar

Embora neste tutorial se tenha controlado dispositivos simples como um botão e um LED, nada impede que se possa usar outros dispositivos de entrada/saída.

Em lugar dum botão poderia ser usado por exemplo um sensor de presença (como o PIR HC-SR505 da figura), um termóstato, em suma algo que fosse capaz de produzir a entrada digital para as placas.

PIR HC-SR505

No caso do dispositivo de saída, em vez do LED poderia ser usada uma eletroválvula, um eletrodoméstico, etc. De notar porém, que estes dispositivos requerem um nível de corrente/tensão incompatíveis com os dos pinos de saída das placas pelo que necessitam dum circuito de interface, em geral baseado num Triac ou Relé.

Neste tutorial será mostrado como se poderia controlar uma lâmpada de 220V a exemplo do que se fez para o caso do LED. O circuito em causa pode ser visto na seguinte imagem, sendo o sinal PWR o responsável por controlar o estado da lâmpada:

power