Botão para desligar Raspberry, ESP8266, Arduino etc

Desligar RPi
Desligar RPi

Botão para desligar

Diferente de microcontroladoras, o Raspberry Pi não deve ser simplesmente desligado da tomada. É necessário fazer o desligamento correto do sistema assim como é feito em sistemas operacionais desktop, mas normalmente as pessoas desligam puxando o fio de maneira inescrupulosa. Desse modo, a cada novo boot é feita uma verificação do sistema de arquivos para reparar o jornalamento e se der sorte, então o sistema finaliza a carga até o shell. Claro, uma hora a sorte acaba, e por isso veremos algumas das muitas soluções possíveis como um botão para desligar boards (Raspberry Pi, Arduino, ESP8266 etc) parecido com um ATX. Quanto às microcontroladas, não há problema algum no desligamento abrupto, porém não é agradável ter que desconectar a fonte da tomada toda a vez que terminar uma brincadeira.

Esse botão para desligar serve para cortar energia também de Arduino, PIC, ESP8266 ou qualquer outro hardware que possua GPIO.

Não é fundamental, já que disponibilizo toda a informação necessária aqui, mas recomendo a leitura desse post sobre interrupções com Raspberry Pi.

 A solução proposta tem variantes, de forma que você pode trocar um dos componentes por outro; explico já, deixe-me primeiro discorrer sobre o que será visto nesse post incluindo suas variantes, para que você molde sua própria ideia tendo por base as que incluo nesse artigo.

O ideal é que através de uma interrupção o RPi faça o desligamento da alimentação, mas você poderia da mesma forma fazê-lo pelo desligamento do sistema na interface, desde que o shutdown seja devidamente configurado para interromper a alimentação.




Não sou especialista em eletrônica, passei a semana me debatendo em busca de uma solução, um amigo de grupos do facebook compilou um modelo (que também exibo mais abaixo), mas assim como meu modelo similar, não funcionou por causa do meu módulo relé, por isso coloco os 2 modos de fazê-lo. Somente hoje (exatos 7 dias de testes e sofrimento) consegui montar uma solução funcional. Tentei com ULN2008, L293D,ULN2803,74HC595 combinados com resistores,capacitores, diodos… O mr Pacman também deu uma solução, mas era complexa demais para mim. Por fim, comecei a estudar o NE555 e logo no modo timer consegui imaginar seu uso para fazer o corte da alimentação. Guarde essa solução em seu bookmark com muito carinho, porque não foi um trabalho trivial para esse humilde maker que vos escreve.

Só pra concluir, minhas especialidades não incluem eletrônica e o maior teste de qualidade que fiz foi colocar o dedo sobre o CI para ver se estava fervilhando. Como não esquentou e a alimentação se manteve, bati o carimbo de aprovado, mas use por sua conta e risco; claro que há um pouco de exagero nessa frase, pois conferí tensão e corrente e justamente por causa da corrente escolhi o modelo empregado nesse projeto.

Desligamento do sistema operacional

Existem diversas maneiras de desligar o sistema operacional:

Além disso, você pode configurar o Ctrl+Alt+Del para desligar o sistema invés de reiniciar. Para isso, edite o arquivo /etc/inittab e mude a linha

Para:

E então você aguarda a mensagem de finalização do shutdown do sistema e aí tira o cabo da energia, caso não deseje fazer os botões, mas não sabia a respeito do correto desligamento.

Mas e se eu estiver sem monitor no RPi?

Nesse caso, você pode colocar um buzzer para tocar ao final do desligamento do sistema. Vou exemplificar como fazê-lo (nesse ou no próximo post, vamos ver até onde minha inspiração me leva). Mas prefira implementar esse desligamento  que se assimila a uma fonte ATX.

E se eu não estiver utilizando teclado no RPi?

Nesse caso, você pode usar um botão tratado com interrupção. E pode utilizá-lo ainda que esteja com monitor e teclado, porque é bastante prático dar um pulso no botão e esperar tudo acontecer. Prefira implementar o botão de desligamento; é cômodo e prazeroso.

Tem como desligar da energia só pelo botão?

É totalmente possível, mas como o hardware não tem esse gerenciamento, a única alternativa que você poderá contar é seu controle externo. Existem diversas soluções diferentes para isso, tentei duas utilizando relés de dois modos diferentes, uma utilizando relé com transistor NPN e por último, a solução apresentada. Lembre-se que pelos meios tradicionais, ainda que o desligamento do sistema seja executado, a board continua alimentada; essa solução é justamente para cortar também o fornecimento de energia para a board e assim mantê-la conectada ao cabo continuamente sem gerar consumo. E vale lembra que o consumo de uma fonte ligada 24/7 durante o ano todo deve consumir menos que um vagalume em busca de uma fêmea no deserto do Saara.

E como desligar o RPi da energia sem tirar da tomada e sem usar relé ou transistor?

Dá sim, mas aí você precisa fazer o desligamento do sistema pelo teclado e receber sinalização pelo buzzer, ou desligar pelo teclado e esperar a mensagem de desligamento no monitor. Depois disso, você pode acionar um interruptor adaptado à sua fonte ou simplesmente utilizar os botões dispostos nesse circuito. Mas convenhamos, somente no travamento do sistema você precisará desligar pelo botão.  O modelo proposto aqui não faria sentido, não fosse o intento de desligar física e logicamente, de maneira digital.

Ambiente e lista de materiais

Para desligar um Raspberry você vai precisar de:

  • 1 interruptor ou;
  • 1 buzzer se optar por interruptor ou se quiser um charme extra.
  • 2 ou 3 botões de estado – Para o ligamento é obrigatório, mas para o desligamento você pode usar a interface do sistema. Um terceiro poderia permitir o desligamento imediato, invés de enviar uma interrupção para a board.
  • 1 mini protoboard (para montar tudo sem solda e fornecer ocasionalmente alguns mal contatos)
  • 1 NE555
  • 1 transistor FET canal N
  • 1 optocopler (ou acoplador ótico, ou fotoacoplador ou…)
  • 2 resistores de 10k
  • 2 resistores de 300
  • 1 resistor de 1k
  • 2 LEDs de 3mm (eu preferi um verde e um vermelho).
  • jumpers

O Linux instalado em minha RPi é o Raspbian. Não sei precisar o quão diferente algum dos processos pode ser em outras plataformas, portanto Raspbian é minha recomendação, mas esse processo pode funcionar também em outras boards Linux que tenham GPIO, mesmo em outras arquiteturas como MIPS.

Preparando o software

Por ser a parte mais simples (só pelo fato de eu não precisar levantar da cadeira), iniciei por aqui. Primeiro vamos a alguns conceitos do sistema operacional que serão utilizados para compor a solução.

Conceitos prévios

O Linux usa um sistema de inicialização de processos por scripts. Esses scripts normalmente ficam em /etc/init.d e são definidas suas inicializações e finalizações através de links simbólicos em /etc/rcX.d, onde X é o nível de inicialização. Para saber seu nível de inicialização, digite:

O meu sistema está iniciando em N2, por isso os exemplos aqui serão baseados no nivel de inicialização do meu sistema.

Talvez você esteja se questionando por qual razão estou falando de nível de inicialização de processo do sistema sendo que o propósito é simplesmente desligá-lo da energia. Mas continue firme na leitura e você entenderá.

Como funciona a ordem de inicialização

Existem diversos scripts de inicialização do sistema, mas eles não podem ser executados em qualquer ordem. O primeiríssimo inicializador do sistema é o init (que pode ou não ser um script, dependendo da construção do sistema operacional e que normalmente está no initrd), depois os outros que também obedecem ordem, conforme suas dependências; isto é, você não pode habilitar um ponto de rede antes de inicializar as configurações de rede e daí por diante. Então, como definir a ordem? – Vejamos um exemplo.

Cabeçalho de um script do init.d
Cabeçalho de um script do init.d

As primeiras linhas seria uma gambiarra para não executar o script na inicialização ainda que ele estiver habilitado para tal. Seguidamente vem o cabeçalho INIT, onde cada campo é mais que um comentário, ele é utilizado para sua inserção na inicialização através de um programa como o update-rc.d, ue pode ser chamado assim:

Quando chamado dessa maneira, ele vai ler as predefinições desse header e inserir a chamada e finalização  dentro de /etc/rcX.d, com o prefixo correspondente. Antes de vermos o padrão dessa inserção, vamos notar os parâmetros desse cabeçalho; ele diz que o daemon é o dhcpcd e requer a inicialização prévia dos serviços contidos na variável $local_fs. Do mesmo modo, ele aguarda a finalização desses mesmos serviços para encerrar. Ele será inicializado nos níveis 2,3,4 e 5 e desligado em 0 (halt), 1 (singleuser) e 6 (reboot).

Como eu já vi que meu runlevel é o 2, vou me ater a esse nível para saber como andam as coisas. Entrando no respectivo diretório:

Links simbólicos
Links simbólicos

Repare que todos os arquivos estão em azul claro, que representa link simbólico. Repare também que alguns arquivos iniciam com ‘K’ (kill) e outros com ‘S’ (start), seguido por números. Esses números definem sua ordem de inicialização ou parada. Logo em seguida está o nome do script que ele está interagindo. O limite numérico é de 2 digitos, como você poderá ver se ler o README contido no mesmo diretório. Então, se quiser interromper um script, você pode fazê-lo de várias maneiras, sendo uma delas renomeando o script para iniciar com ‘K’, seguidamente chamando o update-rc.d para reordenamento.

Dentro de /etc/rcS.d estão outros scripts de inicialização, que são pertinentes ao funcionamento do sistema operacional e possuem níveis de inicialização mais altos.

Poderiamos escrever um script para ser executado por último no desligamento do sistema, porque devemos considerar uma maneira de interromper a energia ou avisar que o sistema pode ser desligado da tomada. Já existe o último processo, que é o halt, mas vejamos a construção de um script de inicialização/finalização de sistema.

Agora vamos falar das duas aplicações possíveis para esse único script. Ele pode tanto interromper um relé quanto acionar um buzzer ou simplemente comutar o estado do NE555 – esse último caso é o nosso pretendido.

Agora vamos ao ovo e a galinha; se eu desligar o relé que é mantido pelo GPIO do Raspberry ligado, como voltarei a ligar o RPi? – Esse foi o sofrimento que carreguei durante a semana; sequer desejei escrever outro artigo durante esses 7 últimos dias, como você deve ter reparado.

O modelo proposto deverá iniciar um aterramento do botão disposto à esquerda  (como mostrado no desenho mais adiante). Se desejar enviar um sinal de desligamento para o RPi, um botão extra será necessário. Eu o adicionarei para gerar evento no sistema, inclusive, o código dos programas a seguir já contempla isso.

 Receita de bolo das conexões




No meu caso, utilizei o GPIO7 como gatilho e assim comutar o estado do NE555, que interromperá de vez a alimentação passante para o VCC de saída. Para informar ao sistema o desligamento, o terceiro  botão apenas fecha o circuito como uma interrupção que estará sendo monitorada por um script python, que reage ao evento iniciando o desligamento. Essa interrupção será tratada no GPIO8. Sei que não é preciso dizer, mas a pinagem abaixo é do Raspberry B; a board que estou utilizando para esse fim.

Pinout Raspberry Pi
Pinout Raspberry Pi

Ainda em relação ao GPIO, recomendo mais uma vez a leitura desse post onde trato exclusivamente desse assunto. De qualquer modo, alguns conceitos tratamos agora.

Conforme o desenho, quando queremos desligar a energia, é necessário colocar o GPIO em OUTPUT e o valor em HIGH. Ao ativar um GPIO, o padrão é INPUT e o valor (obviamente) 0. Isto é, colocando um intermediário para levar a tensão a 0 nos pinos do NE555 atrelados aos botões. O video mostrará mais detalhes, não se preocupe.

Tenha em mente que você precisará de 5V para alimentar o RPi e a corrente mínima é de 1.2A para o modelo B. A solução mais bacana e barata que achei foi montar com o transistor FET canal N porque ele suporta até 4A de corrente e para o RPi 2 recomenda-se 2.5A (quem dirá o 3 que está por aí já). Você deverá  cortar um cabo USB para fazer a alimentação do circuito. Repare nas fotos; o cabo de alimentação da minha fonte tem apenas os fios VCC e GND, portanto foi fácil identificar e fazer uma imenda com jumpers para protoboard. Recomendo. Claro, a entrada do RPi é micro USB e utilizei a ponta do cabo ue cortei, fazendo jumpers da mesma forma. Espero que o desenho do circuito tenha ficado compreensível, mais adiante mostro as fotos da fonte.

NE555 modo biestável com FET canal N
NE555 modo biestável com FET canal N

Como você pode reparar, o processo é simples, só tem fios em excesso.

NE555 em modo biestável

O NE555 é fantástico. Vou escrever alguns posts a respeito em homenagem ao CI que me salvou na questão que perdurou uma semana.

Em modo biestável ele funciona como um botão de estado, permitindo trabalhar como se fosse um interruptor. O jeito que fiz no desenho foi conforme minha pobre compreensão, mas pesquisei mais e disponho essa composição a seguir:

NE555 - modo biestável
NE555 – modo biestável

No video eu mostro o funcionamento e a adaptação, não se preocupe se algo lhe gerar dúvidas. Esse é um circuito simplificado para lhe auxiliar na compreensão do funcionamento. Nele, um botão acende o LED, enquanto o outro o apaga. No modelo acima, o LED verde fica aceso quando a alimentação não estiver em uso. Ao alimentar o RPi, o LED verde se apaga e o LED vermelho se acende.

Adaptando a fonte para o circuito

Como já citado, cortei o cabo da fonte e coloquei jumpers em ambas as partes. Tem duas vantagens nessa adaptação. A ponta do cabo agora pode ser utilizada no RPi ou em qualquer outra board que tenha conexão micro USB, bastando variar a fonte (devido às diferentes necessidades de tensão e corrente). O mesmo para a fonte, que além de poder ser conectada facilmente à protoboard, pode servir como fonte para outras pontas, desde USB normal, macho, fêmea, mini e micro até P2 (se for o caso).

O último processo

Em /etc/init.d/ você encontrará o script halt que faz o desligamento do sistema chamando o comando halt. O problema é que todo o sincronimo é feito por esse comando e para incluir o suporte correto do desligamento por GPIO, será necessário mexer um pouco em seu código. Primeiramente foi necessário descobrir sua origem.

Como descobrir que pacote contém um comando

Nos sabores Debian (incluem-se aí os Ubuntu, Xubuntu, Kubuntu, Mint, etc) você pode descobrir a origem de um programa (a que pacote ele pertence originalmente) com o comando dpkg:

O shutdown faz parte do sysvinit, que é o sistema de inicialização ainda existente e funcional utilizada em sistemas Linux com e sem upstart. Enfim, será necessário mexer no código dele, então mãos à obra. – mas não pense que é só digitar ‘apt-get install’; tive que caçar no Google pelo código do sysvinit e encontrei nessa URL. Baixei o pacote bz2, extraí e fui ao código do halt.c e lendo-o, vi em determinado ponto que ele chama ‘/sbin/shutdown’ que por sorte, faz parte desse mesmo pacote (ufa).

Modificando shutdown.c para desligar o Raspberry Pi

Esse é o programa que finaliza o sistema. Tive que ler até a linha 761 pra entender todo o processo antes de mexer no código e assim evitar fazer alguma besteira.

Final do código de shutdown
Final do código de shutdown

Repare que o código está muito bem escrito e de lógica excepcionalmente organizada. A última chamada é da função instrínsica shutdown(). Dentro da função shutdown, há dois caminhos para a finalização. Um deles é através da função fastdown(), na qual implementaremos o gatilho. A partir da linha 338 o código deve ficar assim:

As macros você pode colocar no início do arquivo:

 

Salve o arquivo, compile e substitua seu shutdown. Simples, não? Nem tanto? – Ok, tem um jeito mais rápido.

Magic keys

O kernel tem um fabuloso recurso que lhe dá controle sobre o sistema por seu intermédio. Esse recurso é chamado ‘magic keys’. Se estiver montando seu sistema, será necessário habilitá-lo no kernelconfig antes de compilar seu kernel. Não vou explicar como compilar um núcleo de sistema nesse post, mas a dica é simples. Quando estiver no menu de opções (seja por linha de comando ou pelo emnu em Curses), vá no menu ‘kernel hacking’ e habilite-o de forma que esteja disponível por padrão. O valor 0x01 habilita todos os recursos do SysRq, 0 desabilita. Não será necessário fazê-lo para o RPi porque já está configurado por padrão, mas caso utilize esse tutorial em outra board com um sistema diferente, é bom verificar.

kernel hacking -> Magic SysRq key
kernel hacking -> Magic SysRq key

Esse recurso é normalmente acessado através da combinação de teclas Alt+SysRq+CHAVE, onde CHAVE é o comando pretendido. Por exemplo, seu sistema se tornou indisponível porque o chrome comeu a memória, o disco, a placa de video e o mouse. Você usa Alt+SysRq+B e imediatamente o computador reinicia. Mas obviamente isso traria uma consequência; a verificação do sistema de arquivos e, na melhor das hipóteses, sua recuperação. Por isso que, para ações emergenciais é utilizada a sequência REISUB.

unRaw

Retoma o controle do keyboard.

tErminate

Manda mensagem para todos os processos finalizarem.

kIll

Mata todos os processos.

Sync

Sincroniza os dados pro disco pra não danificar o sistema de arquivos.

Unmount

Remonta o sistema de arquivos em read-only.

reBoot

Faz um elegante e imediato reboot.

Mas não queremos reboot, nem controle do teclado e nem usar o teclado, certo? Pois bem, vamos enviar esses sinais para o kernel por linha de comando. Utilizando o script a seguir, você não precisará compilar nada, apenas montar o circuito tal qual exemplificado acima, ou como no modelo com o relé, feito nesse projeto pelo Waldyr, utilizando um módulo relé da GBK, que tem uma resposta diferente do módulo relé que possuo. O site do Waldyr é www.wix.com/projeletronicos/projetoseletronicos, mas você pode encontrá-lo  também no Facebook . Assim como em seu projeto, inseri o optocopler, o que dá uma segurança extra ao RPi. Pra finalizar esse parágrafo, gostaria de sugerir a leitura da documentação do kernel para que tenha maior intimidade com o recurso (/usr/src/linux/Documentation/sysrq.txt).  Concluo essa parte com uma pequena dica; o suporte (ainda que compilado no kernel) pode precisar de habilitação prévia pra funcionar. Não é o caso do Raspbian, mas se seu Linux não responder aos comandos (ou não existir o arquivo /proc/sysrq-trigger), execute a seguinte linha:

Nas versões mais atuais do kernel há bem mais do que habilitar e desabilitar as Magic keys. Se quiser fazer uma habilitação seletiva das chaves, leia a documentação supracitada.

Script para desligamento do sistema

Para desligar o sistema, combinamos os comandos de GPIO aos comandos das Magic keys, resultando em um script simples de sequência de comandos.

O script tem a finalidade de simplesmente arrolar a sequência de execuções necessárias e ao final será chamado por outro script, que monitorará a interrupção. Eu sei que é chato fica adentrando em teorias, mas como já li alguns comentários em relação ao post sobre interrupções no RPi, me sinto obrigado a explicitar uma questão; o RPi não é um sistema de tempo-real e seu hardware não é projetado para esse propósito, portanto, quando falo de interrupção estou falando de polling, seja ele por um evento secundário do kernel, uma thread no user space ou um programa via interpretador de comandos. Não importa, vamos tratar como interrupção para fazer um co-relacionamento transparente entre uma microcontroladora e esse microprocessador ARM.

Se o script for abortado durante a execução, você pode eliminar o ‘kill’ e modelar conforme sua necessidade. Mas além disso, é necessário ter certeza do modo de operação das Magic Keys, como citado mais acima.

Criar script de serviço do sistema




Já discorri a respeito anteriormente (talvez até mais de uma vez), agora é hora de criar o script que será um serviço de sistema, inicializando a cada boot. Além disso, será necessário que esse serviço monitore os eventos no GPIO e para tal, ele precisará ler um arquivo de configuração. Para que tudo esteja dentro dos padrões, precisamos então das seguintes características:

  • script de inicialização de serviço devidamente configurado
  • script (programa) invocado por ele, com o propósito de monitorar o GPIO
  • arquivo de configuração em /etc, com as variáveis de GPIO pertinentes ao monitoramento.

Script de inicialização

A princípio implementei apenas as funções ‘stop/start’, sinta-se livre para implementar a opção ‘status’ ou outra mais que queira.

Para adicioná-lo ao startup, crie-o com o nome desejado em /etc/init.d/. O nome ‘powerOffMonitor’ é uma sugestão que pode tranquilimente ser modificada a seu gosto. Dê permissões de execução (chmod 750 <script>) e adicione-o com ao startup:

 

Programa de monitoramento de interrupções

Não seria ‘interrupções’; na verdade, é 1 interrupção que esse script vai monitorar. Não precisa ser em Python, pode ser shell script, C ou seja lá a linguagem que preferir. Eu reaproveitei o código do post sobre interrupções (que já sugeri a leitura duas vezes, então não vou repetir o link para evitar de aborrecê-lo):

Arquivo de parâmetros

Esse arquivo deve ficar em /etc conforme o script acima que o invoca: “source /etc/interrupts.conf”. Esse arquivo pode conter funções que resolvam valores para variáveis, mas nesse caso um header “#!/bin/sh” será necessário. Ainda que não seja o caso, o incluí no arquivo:

Antes de implementarmos tudo, veja a solução proposta pelo Waldyr no video a seguir. Nele, você só não vê a costa do relé, que é exatamente o dessa imagem:

Parte de tras do relé da GBK
Parte de tras do relé da GBK

No video você entenderá melhor porque essa ligação um tanto diferente dos padrões. Já adianto; não serve em qualquer relé. Tentei fazer o loop de outro modo, depois desse modo recomendado pelo Waldyr, mas meu relé não desarmava de modo algum, mesmo incluindo os respectivos resistores. Agora que atuei com o FET, acredito que seria possível utilizá-lo para dar a carga suficiente para seu desarme, porém ficou bem mais econômico na solução atual. Se preferir utilizar um relé (que também é muito legal), tente seguir a orientação do Waldyr no video que segue.

Empolgante, não? Apesar de mais barato, minha solução é composta por mais componentes (talvez não mais, mas um módulo relé é considerado como uma coisa só, independente do conjunto eletrônico). Veja a minha prova de conceito também:

 

Agora que temos todas as fases necessárias concluídas, você pode optar pelo meio físico preferido através desses projetos dispostos. Tive sete dias duros e sofridos me embrenhando em meio a informações que não me davam caminho algum por falta de conhecimento em eletrônica, mas estudei muitos componentes nesse periodo e acabei reforçando um pouco minha base de eletrônica para mais projetos divertidos!

Eu ia deixar esse post para a próxima semana porque só consegui concluir esse circuito no domingo e ainda falta chegar o optocopler, que vai atuar no circuito. Além disso, não coloquei ainda um botão para o gpio8 (tenho aos montes), então farei o seguinte; estou disponibilizando esse artigo para que você já possa ir montando o seu (de repente fica pronto antes de chegar meus fotoacopladores). Prometo que mostro o funcionamento completo assim que eu voltar dessa semana de férias (que se inicia hoje) e pra não ser apenas um post complementar, já farei o código para Arduino e para ESP8266. Inclusive para o ESP8266 tem a regulação da tensão, será divertido um post a mais sobre esse assunto.

A fonte que modifiquei para esse projeto será mostrada no próximo post (porque não fiz as fotos e estou com preguiça de desconectá-lo lá da protoboard, que está além do alcance do meu braço), assim também já mostro a troca da fonte do RPi (5V) para o Arduino (9V no jack). Depois com o ESP8266, utilizando um regulador de tensão ou uma fonte regulável DC/DC, não sei ao certo ainda o que escolherei.

Pra finalizar essa primeira parte, gostaria de citar mais uma vez que minha especialidade não é eletrônica e, baseando-se nessa ideia, você leitor pode sugerir implementações diferentes, modificações, sugestões e críticas (se não for construtiva, nem aprovo o comentário). De repente, dá pra fazer o circuito mais simples ainda!

Inscreva-se no nosso newsletter, alí em cima à direita e receba novos posts por email.

Siga-nos no Do bit Ao Byte no Facebook.

Prefere twitter? @DobitAoByte.

Inscreva-se no nosso canal Do bit Ao Byte Brasil no YouTube.

Próximo post a caminho!

Comments

comments

Djames Suhanko

Djames Suhanko é Perito Forense Digital. Já atuou com deployer em sistemas de missão critica em diversos países pelo mundão. Programador Shell, Python, C, C++ e Qt, tendo contato com embarcados ( ora profissionalmente, ora por lazer ) desde 2009.

Um comentário em “Botão para desligar Raspberry, ESP8266, Arduino etc

Deixe uma resposta