Fazendo um controlador para uma casa inteligente

Fazemos um controlador para uma casa inteligente e não apenas.

Em um artigo anterior, descrevi o desenvolvimento do sistema como um todo. Nele, descreverei o desenvolvimento de um controlador responsável por sensores de sondagem e módulos de E / S. "Por que reinventar a roda?" - você pergunta. Em primeiro lugar, é interessante e, em segundo lugar, estranhamente, não existe uma solução OpenSource para esse controlador que cubra software e hardware. O artigo é destinado a pessoas que são um pouco versadas em eletrônica e no desenvolvimento de Linux embarcado.

Fazer um controlador, você diz, é tão complicado - você precisa montar um quadro, escrever um software, imprimir o estojo. Mas, na realidade, tudo é um pouco mais complicado, foi isso que me serviu, mas você está certo em princípio:

1. hardware do controlador

- escolha da placa da CPU para o controlador
- escolha do controlador IO
- escolha da fonte de alimentação
- diagrama de blocos do controlador
- desenvolvimento de uma placa cruzada para o controlador
- desenvolvimento de placas para módulos RS-485
- produção de placas

2. software para o controlador

- escolha do sistema de compilação para kernel linux e rootfs
- estrutura de partição do cartão SD
- escolha do gerenciador de inicialização e carregamento dos rootfs necessários
- mudanças na árvore de dispositivos
- a escolha de um sistema para cobrança de débitos negociados
- escrevendo um sistema de construção
- escrevendo um núcleo de comunicação
- escrevendo gateway mqtt (pontos do controlador discreto / analógico -> tópicos mqtt)
- escrevendo um analisador do Google e construindo um arquivo de configuração json para o gateway
- escrevendo um monitor de ponto para acessar os pontos do controlador
- montar sistema de arquivos somente leitura

3. caixa do controlador

- o que deveria ser: conectores, refrigeração, assentos para uma prancha, hipotecas de clipes para suportes em um dinrake.
- design e impressão

Algumas palavras sobre o hardware.

Provavelmente, apenas os mais desesperados agora usam um processador separado, memória, flash, controlador de energia, mais algumas centenas de componentes e começam a esculpir tudo isso juntos. O resto usa os frutos do trabalho de outras pessoas, é mais rápido e fácil. Você só precisa abrir um navegador e escrever "computador de placa única" e passar o resto do dia escolhendo o caminho certo. Eu precisava de muitas portas seriais e é desejável que a placa suporte -40 ° C a + 85 ° C, então a escolha foi feita no BeagleBone Black (BBB). Também no BBB, todos os periféricos são conectados a dois conectores PBD de 46 pinos em incrementos de 2,54, o que é conveniente para a criação de protótipos e o desenvolvimento de uma placa cruzada. É necessária uma placa cruzada para combinar todos os componentes em uma placa; para mim, é uma placa de CPU, uma fonte de alimentação, um controlador IO e placas de canal RS485. Além disso, é a placa cruzada que precisa ser fixada ao gabinete e há conectores nele para alimentação e cabo RS485.



Assim, como descobrimos a placa da CPU, a próxima coisa a decidir é se é necessário colocar um controlador de entrada / saída (IO) na placa cruzada ou não. Coloquei-o no quadro e ainda não o usei com sucesso. A única coisa que ele faz é adiar o início do BBB por 1s após aplicar energia e acionar o botão de reinicialização.

A fonte de alimentação para o controlador, eu peguei o MeanWell NSD10-12S5 já pronto, desenvolvê-lo para um único dispositivo é uma tarefa sem sentido, apenas peguei para consumo e é isso. Não preste atenção no LCD, ele está no quadro, mas eu não implementei suporte.





Algumas palavras sobre placas de canal RS485.

Existem 4 interfaces seriais BBB na placa cruzada. Então, aí você pode colocar qualquer tipo de canal que precisar, módulo RS485, CAN, Zigbee ...

Eu precisava de canais RS485, então os fiz apenas, eles estão com controle automático de recepção / transmissão e com isolamento galvânico. Por que não usar o controle do transceptor com BBB, porque a TI parou oficialmente de suportar o estroboscópio para RS485 no driver de dispositivo serial. Você pode encontrar um patch para o driver, pode adicioná-lo, mas por quê? Tendo tornado o canal autotravável, ele pode ser colocado em qualquer placa, por exemplo, no RaspberyPi, onde nunca houve esse suporte, se houver, então me corrija. O estroboscópio para o driver rs485 está configurado no attiny10, barato e alegre.

Voltamos ao software.

Escolhendo um sistema de compilação para o kernel do linux e o rootfs.

Existem vários sistemas desse tipo, os mais populares são o Yocto e o BuildRoot. Se você precisa desenvolver um projeto grande, se tem muito tempo e deseja escrever receitas, o Yocto é a sua escolha. Com a ajuda do BuildRoot, você pode coletar tudo o que precisa para iniciar o fórum facilmente, muito, muito simples, porque Estou criando um sistema no Beaglebone Black (a seguir BBB) então:

  1. leia o que está escrito aqui habr.com/en/post/448638
  2. fazer limpo
  3. make beaglebone_defconfig
  4. fazer

Isso é tudo. Agora tudo o que você precisa para executar o quadro está na pasta / buildroot / output / images.

Tudo parece muito simples e não é interessante, então você pode fazer um pouco mais complicado:

  1. integre o buildroot ao seu sistema de construção, faça o download com um script, lembre-se de usar uma tag estável e não faça o último desenvolvimento
  2. escreva seu defconfig e jogue o script na pasta / buildroot / configs antes de montar o buildroot, não esqueça que todos os defconfigs devem terminar com * _defconfig, caso contrário o buildroot não o vê
  3. copie seu post-build.sh para board / beaglebone / post-build.sh
  4. faça preparar um script que fará n1, n2 e n3 para você

Como resultado, o buildroot irá gerar zImage e rootfs.tar

Selecionando a estrutura da partição do cartão SD:

Acho que não é necessário focar muita atenção nisso.
Fiz 4 seções BOOT / ROOT_1 / ROOT_2 / DATA.
A seção BOOT contém tudo o que você precisa para inicialização: MLO, barebox.bin, barebox.env, am335x-boneblack.dtb, zImage, boot.txt.

ROOT_1 e ROOT_2 contêm rootfs, cuja seleção é inserida no arquivo boot.txt (veja abaixo). Todas essas partições são montadas como somente leitura para evitar falhas no sistema de arquivos quando a energia é desligada. DATA contém configurações de design, ao alterar as quais não há necessidade de reconstruir o código.

Essa estrutura de partições no futuro facilitará a gravação de um componente de atualização de software. Este componente substituirá uma das seções ROOT_1 / ROOT_2, que não é usada agora e, em seguida, altere o arquivo boot.txt se você não precisar alterar o kernel.

Escolhendo um gerenciador de inicialização.

Eu tive muitas experiências com bootloaders para BBB. No começo, usei, como todo mundo, o U-Boot que o BuildRoot gera. Mas eu não gostei, talvez, é claro, isso seja uma questão de hábito, mas me pareceu que era demais, muito pesado e difícil de configurar. Então, pensei que não seria uma má idéia iniciar o sistema rapidamente, em 2 a 3 segundos, e arquivar o X-Loader para que ele carregasse o kernel, consegui, mas novamente houve um problema de configuração e a hora de início para mim. não é crítico (o sistema no systemd inicializa lentamente por si só, mesmo se você excluir tudo o que não é necessário).

No final, decidi pelo barebox, gostei muito da sua simplicidade, além de o site ter toda a documentação (www.barebox.org).

Por exemplo, para carregar rootfs da primeira ou segunda partição, você só precisa:

1. na seção de inicialização, crie o arquivo boot.txt que exportará uma variável do tipo "export BOOT_NUM = X"

2. crie dois scripts / env / boot / sdb1 / env / boot / sdb2 para descrever as opções de inicialização, por exemplo:

echo "botting with mmcblk0p2 as rootfs..." global.bootm.image=/boot/zImage global.bootm.oftree=/boot/am335x-boneblack.dtb global.linux.bootargs.console="console=ttyO0,115200" global.linux.bootargs.debug="earlyprintk ignore_loglevel" global.linux.bootargs.base="root=/dev/mmcblk0p2 ro rootfstype=ext4 rootwait" 

3. crie um script / env / boot / sd no qual, dependendo do BOOT_NUM, inicie o script sdb1 ou sdb2

4. defina a variável boot.default

 nv boot.default=sd saveenv 

5. Alterando ainda mais o BOOT_NUM no boot.txt, carregaremos o rootfs da primeira ou segunda partição, que no futuro poderá ser usada para atualização de software.

Alterações na árvore de dispositivos.

Como eu uso o MODBUS RTU via RS485 para me comunicar com os módulos, eu precisava habilitar quase todas as portas seriais existentes no BBB. Para fazer isso, é necessário reativá-los na árvore de dispositivos, porque Por padrão, a maioria deles está desativada.

Seria correto fazer o seu patch para o arquivo am335x-bone-common.dtsi do pacote buildrut e aplicá-lo todas as vezes antes de montá-lo, mas a preguiça venceu e eu apenas peguei todos os arquivos necessários, alterei tudo o que precisava e construí-o com as mãos.

Porque isso é feito uma vez, é possível e assim:

1. Crie uma pasta com os arquivos necessários para a montagem:

 am335x-bone-common.dtsi am335x-boneblack-common.dtsi am335x-boneblack.dts am33xx-clocks.dtsi am33xx.dtsi am33xx.h gpio.h omap.h tps65217.dtsi 

2. No arquivo am335x-bone-common.dtsi, você precisa configurar corretamente os pinos e desabilitar os drivers da porta:

 uart1_pins: pinmux_uart1_pins { pinctrl-single,pins = < AM33XX_IOPAD(0x980, PIN_INPUT_PULLUP | MUX_MODE0) AM33XX_IOPAD(0x984, PIN_OUTPUT_PULLDOWN | MUX_MODE0) >; }; uart2_pins: pinmux_uart2_pins { pinctrl-single,pins = < AM33XX_IOPAD(0x950, PIN_INPUT_PULLUP | MUX_MODE1) AM33XX_IOPAD(0x954, PIN_OUTPUT_PULLDOWN | MUX_MODE1) >; }; uart4_pins: pinmux_uart4_pins { pinctrl-single,pins = < AM33XX_IOPAD(0x870, PIN_INPUT_PULLUP | MUX_MODE6) AM33XX_IOPAD(0x874, PIN_OUTPUT_PULLDOWN | MUX_MODE6) >; }; uart5_pins: pinmux_uart5_pins { pinctrl-single,pins = < AM33XX_IOPAD(0x8C4, PIN_INPUT_PULLUP | MUX_MODE4) AM33XX_IOPAD(0x8C0, PIN_OUTPUT_PULLDOWN | MUX_MODE4) >; }; &uart1 { pinctrl-names = "default"; pinctrl-0 = <&uart1_pins>; status = "okay"; }; &uart2 { pinctrl-names = "default"; pinctrl-0 = <&uart2_pins>; status = "okay"; }; &uart4 { pinctrl-names = "default"; pinctrl-0 = <&uart4_pins>; status = "okay"; }; &uart5 { pinctrl-names = "default"; pinctrl-0 = <&uart5_pins>; status = "okay"; }; 

3. Em seguida, um pouco de mágica e o arquivo finalizado am335x-boneblack.dtb fica no mesmo diretório:

 a. sudo apt-get install device-tree-compiler 

b. execute o pré-processador:

 cpp -Wp,-MD,am335x-boneblack.dtb.d.pre.tmp -nostdinc -Iinclude -Isrc -Itestcase-data -undef -D__DTS__ -x assembler-with-cpp -o am335x-boneblack.dtb.dts.tmp am335x-boneblack.dts 

c. execute o próprio compilador:

 dtc -O dtb -o am335x-boneblack.dtb -b 0 -i src -d am335x-boneblack.dtb.d.dtc.tmp am335x-boneblack.dtb.dts.tmp 

4. am335x-boneblack.dtb deve ser colocado na partição de inicialização ao lado do kernel e, no script de inicialização do barebox, adicione a seguinte linha - " global.bootm.oftree=/boot/am335x-boneblack.dtb "

Escolha de um sistema para cobrança de débitos negociados.

Como você sabe, os sistemas sem erros não existem, bem como a análise de um sistema multithread sem rastreios. É muito conveniente que esses rastreamentos não sejam exibidos simplesmente no console, mas sejam coletados usando algo especialmente criado para isso, para que seja possível classificá-los por processos, aplicar filtros etc. E eu apenas conheço um bom sistema que é fácil de construir sob host e destino. Esse é o DLT, se você nunca ouviu falar disso, não importa, todas as lacunas de conhecimento podem ser facilmente cobertas lendo em.projects.genivi.org/wiki/display/PROJ/Diagnostic+Log+e+Trace .
Este sistema consiste em dlt-daemon e dlt-viewer. Como o nome indica, o dlt-daemon é executado no destino e o dlt-viewer no host. Além de tudo isso, para o seu binário, do qual queremos coletar rastros, você precisa vincular a dlt lib.



Em geral, tudo é conveniente, como coletar traços e analisá-los, eu recomendo.

Escrevendo um sistema de compilação.

Por que escrever um sistema de construção, porque você pode fazer o download de tudo dos repositórios, construí-lo com suas mãos, construir com base nesse rootfs e véu, o controlador funciona. Mas repetir esse truque em um mês será mais difícil e em dois - isso geralmente é impossível. Novamente, você deve se lembrar do que, onde colocar, o que construir e como começar. Portanto, tendo passado muito tempo no início, você o salva mais tarde, além de ter a oportunidade de criar convenientemente sob host e destino. O sistema de compilação consiste em um conjunto de scripts que primeiro preparam o host para a compilação, baixam componentes de terceiros, como buildroot, mosquitto, daemon DLT, de seus repositórios, compilam e colocam em seus lugares. E então você pode iniciar a construção do seu projeto. Se a construção sob o host não for difícil de executar, você sempre precisará mexer com a construção sob o destino, e seria melhor se o script fizesse isso.

O Buildroot pode ser configurado para chamar um script pós-build após formar rootfs, que estará no buildroot / output / target. Isso oferece uma ótima oportunidade de colocar tudo o que você precisa lá. E então, a imagem do sistema de arquivos já conterá tudo o que você precisa para iniciar o sistema.

A receita é algo como isto:

  1. você precisa copiar seus binários em algum lugar em buildroot / output / target, por exemplo em / opt / bin
  2. se houver configurações, faça o mesmo com elas, apenas em / opt / etc
  3. copiar binários de terceiros, para mim é mosquitto, DLT daemon, suas bibliotecas e configurações
  4. Para iniciar o próprio sistema ao carregar o controlador, é necessário copiar os serviços do systemd, é melhor combiná-los no seu destino e reativá-lo, criando um link simbólico para vários usuários.
  5. copie o fstab modificado (por que, depois eu digo)

Depois disso, basta descompactar buildroot / output / images / rootfs.tar na seção desejada do cartão SD e ligar a alimentação.

 build git repo: https://github.com/azhigaylo/build 

Escrevendo um núcleo de comunicação.

O conceito disso é tão antigo quanto o próprio modbus.

Cada dispositivo de E / S em uma rede modbus possui (16 bits) registros disponíveis para leitura, leitura / gravação, nos quais os dados são armazenados e através dos quais esses dispositivos são controlados. O controlador, por sua vez, possui matrizes de pontos discretos (status e valor de bytes) e analógicos (status e valor flutuante), nos quais armazena o estado de todos os parâmetros.

Portanto, a tarefa do núcleo de comunicação é simples - coletar dados de dispositivos de E / S usando o protocolo modbus, mapeá-los para pontos do controlador e fornecer acesso a esses pontos para o nível superior. E se você precisar gerenciar alguma coisa, tudo estará na outra direção - o dispositivo lógico (mais sobre isso posteriormente) deve ser inscrito no ponto do controlador e a gravação nesse ponto inicia a conversão desse parâmetro no dispositivo físico de saída de água.



Para estruturar de alguma forma os dados e trabalhar com dispositivos, você pode introduzir o conceito de um dispositivo lógico que exibirá o estado de um dispositivo físico em seu software.

Também decidi dividir os dispositivos lógicos em dois grupos:

  1. Padrão (módulos Aries de entrada / saída discreta), para os quais os números de modbus registram dados são conhecidos com antecedência, e basta determinar os pontos do controlador onde os dados serão salvos.
  2. Dispositivos do usuário, para eles é necessário descrever independentemente o mapeamento dos registradores modbus para os pontos do controlador.

De todas as opções acima, é lógico ter algum tipo de configurador para o controlador, seja apenas uma configuração json ou uma ferramenta auto-escrita que gera uma configuração binária, qualquer coisa que seja conveniente. Eu tenho a segunda opção, porque havia idéias para escrever um núcleo de comunicação para que ele pudesse ser executado facilmente não apenas na placa Linux, mas também no Arduin com FreeRtos, alterando o nível PAL no software.

No configurador de cada dispositivo, você precisa definir o número da porta do controlador rs485, o endereço do dispositivo e o ponto do controlador no qual o status da comunicação com o dispositivo é exibido, além de cada dispositivo padrão em que seus canais são descritos e, para um dispositivo de usuário, seus registros são mapeados para pontos.





Esse arquivo de configuração, contendo todos os dados necessários na construção da rede modbus, permite que você não modifique o código fonte do projeto, se precisar adicionar / remover / alterar dispositivos de entrada / saída, basta alterar os parâmetros no configurador e salvá-los no arquivo de configuração.

Na inicialização, o núcleo de comunicação analisa a configuração e cria com base em listas de dispositivos lógicos para cada porta rs485 do controlador, em seguida, os threads são criados em cada porta e uma pesquisa cíclica de dispositivos físicos é iniciada.

 core git repo: https://github.com/azhigaylo/homebrain_core 

Escrevendo o gateway mqtt.

Na verdade - seus pontos de controle, discretos e analógicos, com uma interface proprietária para acesso a eles, são de pouco interesse para ninguém. Portanto, há apenas uma saída - mqtt. Acho que não exagerarei se disser que atualmente é o protocolo mais comum para a troca de pequenas mensagens, além de ser muito simples e compreensível de usar. Então, quando eu precisava transmitir dados do controlador - não pensei muito sobre o que usar.



Porque Eu tenho muitos parâmetros, sempre houve confusões no arquivo de configuração do gateway, onde o mapeamento do controlador aponta para os tópicos do gateway mqtt foi registrado. O Google ajudou a tabela e gravou um analisador csv dessa tabela no arquivo de configuração json do gateway.



repositório git de gateway
analisador git repo

Monitor de ponto de escrita.

Às vezes, é muito útil ver o que está acontecendo com os pontos do controlador. Para isso, escrevi um pequeno aplicativo que se conecta diretamente ao núcleo da comunicação e lê o status de pontos discretos e analógicos. Eu sou muito firme com a interface do usuário, então, de alguma forma, pude lançar o aplicativo no QML, ele funcionou com um rangido, você pode contar o ponto, pode escrever, mas não preciso de mais.

 pointmonitor git repo: https://github.com/azhigaylo/pointmonitor 

Monte o sistema de arquivos somente leitura.

Geralmente, poucas pessoas prestam atenção a isso e, mesmo em projetos de produção, você pode encontrar dispositivos nos quais a partição com rootfs é gravável. Isso mais cedo ou mais tarde leva à falha de qualquer sistema de arquivos, mesmo o mais estável. Porque Como o controlador pode ser desligado a qualquer momento, é apenas uma questão de tempo / caso quando isso acontece. Para minimizar essa probabilidade, você precisa mexer um pouco com o fstab e, antes de criar a imagem rootfs, coloque-a lá, como descrito acima. No fstab, primeiro, você precisa montar o sistema de arquivos como somente leitura e, segundo, tudo o que pode mudar pode ser mapeado no tmpfs.

Meu fstab é este, pode ser diferente para você:

 /dev/root / auto ro 0 1 tmpfs /tmp tmpfs nodev,nosuid,size=50M 0 0 tmpfs /srv tmpfs nodev,size=50M 0 0 tmpfs /var/log tmpfs defaults,noatime,size=50M 0 0 tmpfs /var/tmp tmpfs defaults,noatime,size=50M 0 0 tmpfs /var/run tmpfs defaults,noatime,size=50M 0 0 tmpfs /var/lib tmpfs defaults,noatime,size=10M 0 0 

Corpo do controlador

Há muito tempo, uma impressora 3D é incluída nas seções do cabeçalho de cada engenheiro coletivo de agricultores, infelizmente eu não a tenho, mas ela está funcionando. Recentemente, a empolgação de outros funcionários por ele desapareceu. Eu uso isso ao imprimir tudo o que preciso e o que não preciso; você pode se convencer disso lendo o meu post anterior.

Desenhamos no FreeCAD, geramos o gcode no Cura e obtemos um estojo, sem esquecer de fazer assentos para o quadro, recortes para conectores e refrigeração e hipotecas para clipes em um trilho dinâmico.





Bem, isso é tudo, agora temos uma placa, software em um cartão SD e um gabinete. Pegamos um arquivo (não estou brincando) e conectamos tudo, conectamos a alimentação, os cabos RS485 e tudo começa a funcionar. E você disse difícil, difícil ...

Source: https://habr.com/ru/post/pt462259/


All Articles