Faire un contrôleur pour une maison intelligente

Nous fabriquons un contrôleur pour une maison intelligente et pas seulement.

Dans un article précédent, j'ai décrit le développement du système dans son ensemble. Dans ce document, je décrirai le développement d'un contrôleur responsable de l'interrogation des capteurs et des modules d'E / S. "Pourquoi réinventer la roue?" - demandez-vous. Premièrement, c'est intéressant, et deuxièmement, curieusement, il n'y a pas de solution OpenSource pour un tel contrôleur couvrant à la fois le logiciel et le matériel. L'article est destiné aux personnes qui connaissent un peu l'électronique et le développement Linux embarqué.

Faire un contrôleur, dites-vous, est si compliqué - vous devez faire une carte, écrire un logiciel, imprimer le boîtier. Mais en réalité, tout est un peu plus compliqué, c'est ce que ça m'a apporté, mais vous avez raison en principe:

1. matériel du contrôleur

- choix de la carte cpu pour le contrôleur
- choix du contrôleur IO
- choix de l'alimentation
- schéma fonctionnel du contrôleur
- développement d'un tableau croisé pour le contrôleur
- développement de cartes pour modules RS-485
- production de planches

2. logiciel pour le contrôleur

- choix du système de construction pour le noyau linux et rootfs
- structure de partition de la carte SD
- choix du bootloader et chargement des rootfs nécessaires
- changements dans l'arborescence des appareils
- le choix d'un système de collecte des débits négociés
- écrire un système de build
- écrire un noyau de communication
- écriture de la passerelle mqtt (points de contrôleur discrets / analogiques -> rubriques mqtt)
- écrire un analyseur Google et créer un fichier de configuration json pour la passerelle
- écrire un moniteur de points pour accéder aux points du contrôleur
- monter le système de fichiers en lecture seule

3. boîtier de contrôleur

- ce qui devrait être, connecteurs, refroidissement, sièges pour une planche, hypothèques pour clips pour supports sur un dinrake.
- conception et impression

Quelques mots sur le matériel.

Probablement, seuls les plus désespérés prennent maintenant un processeur séparé, une mémoire, un flash, un contrôleur d'alimentation, quelques centaines de composants supplémentaires et commencent à tout sculpter ensemble. Les autres utilisent les fruits du travail des autres, c'est plus rapide et plus facile. Il vous suffit d'ouvrir un navigateur et d'écrire «ordinateur monocarte» et de passer le reste de la journée à choisir le bon. J'avais besoin de beaucoup de ports série et il est souhaitable que la carte supporte -40 ° C à + 85 ° C, donc le choix s'est porté sur BeagleBone Black (BBB). Toujours sur BBB, tous les périphériques sont connectés à deux connecteurs PBD de 46 broches par incréments de 2,54, ce qui est pratique pour le prototypage et le développement d'une carte croisée. Une carte croisée est nécessaire pour combiner tous les composants sur une seule carte, pour moi, c'est une carte CPU, une alimentation, un contrôleur IO et des cartes de canaux RS485. De plus, c'est la carte transversale qui doit être fixée au boîtier et il y a des connecteurs pour l'alimentation et le câble RS485.



Donc, nous avons compris la carte CPU, la prochaine chose à décider est de savoir s'il est nécessaire de mettre un contrôleur d'entrée / sortie (IO) sur la carte transversale ou non. Je l'ai posé sur le plateau et je ne l'ai pas encore utilisé avec succès. La seule chose qu'il fait est de reporter le démarrage du BBB pendant 1s après avoir mis sous tension et sert le bouton de réinitialisation.

L'alimentation du contrôleur, j'ai pris le MeanWell NSD10-12S5 prêt à l'emploi, le développer pour un seul appareil est une entreprise vide de sens, je viens de le ramasser pour la consommation et c'est tout. Ne faites pas attention à l'écran LCD, il est sur la carte, mais je n'ai pas implémenté de support.





Quelques mots sur les cartes canaux RS485.

Il y a 4 interfaces BBB série sur la carte croisée. Vous pouvez donc y mettre tout type de canal dont vous avez besoin, RS485, CAN, module Zigbee ...

J'avais besoin de canaux RS485, donc je les ai faits uniquement, ils sont avec contrôle automatique de transmission / réception et avec isolation galvanique. Pourquoi ne pas utiliser le contrôle de l'émetteur-récepteur avec BBB, car TI a officiellement arrêté de prendre en charge le stroboscope pour RS485 dans le pilote de périphérique série. Vous pouvez trouver un patch pour le pilote, vous pouvez l'ajouter vous-même, mais pourquoi? Après avoir rendu le canal autobloquant, vous pouvez le placer sur n'importe quelle carte, par exemple sur RaspberyPi, où il n'y a jamais eu un tel support, s'il y en avait, corrigez-moi. Le stroboscope pour le pilote rs485 est configuré sur attiny10, bon marché et joyeux.

Nous revenons au logiciel.

Choisir un système de construction pour le noyau linux et rootfs.

Il existe plusieurs systèmes de ce type, les plus populaires sont Yocto et BuildRoot. Si vous avez besoin de développer un grand projet, si vous avez beaucoup de temps et que vous souhaitez écrire des recettes, alors Yocto est votre choix. Avec l'aide de BuildRoot, vous pouvez collecter tout ce dont vous avez besoin pour un simple lancement de la carte est très, très simple, car Je fais un système sur Beaglebone Black (ci-après BBB) puis:

  1. lire ce qui est écrit ici habr.com/en/post/448638
  2. nettoyer
  3. faire beaglebone_defconfig
  4. faire

C’est tout. Maintenant, tout ce dont vous avez besoin pour faire fonctionner la carte se trouve dans le dossier / buildroot / output / images.

Tout semble très simple et pas intéressant, vous pouvez donc faire un peu plus compliqué:

  1. intégrez buildroot dans votre système de build, téléchargez-le avec un script, n'oubliez pas d'utiliser une balise stable et de ne pas prendre le dernier développement
  2. écrivez votre defconfig et lancez le script dans le dossier / buildroot / configs avant d'assembler buildroot, n'oubliez pas que tous les defconfigs doivent se terminer par * _defconfig, sinon buildroot ne le voit pas
  3. copiez votre post-build.sh dans board / beaglebone / post-build.sh
  4. faire préparer un script qui fera n1, n2 et n3 pour vous

Par conséquent, buildroot générera zImage et rootfs.tar

Sélection de la structure de partition de la carte SD:

À ce sujet, je pense qu'il n'est pas nécessaire de concentrer beaucoup d'attention.
J'ai fait 4 sections BOOT / ROOT_1 / ROOT_2 / DATA.
La section BOOT contient tout ce dont vous avez besoin pour l'amorçage: MLO, barebox.bin, barebox.env, am335x-boneblack.dtb, zImage, boot.txt.

ROOT_1 et ROOT_2 contiennent des rootfs, dont la sélection est écrite dans le fichier boot.txt (voir ci-dessous). Toutes ces partitions sont montées en lecture seule pour éviter les pannes du système de fichiers lorsque l'alimentation est coupée. DATA contient des configurations de conception, lors de la modification, il n'est pas nécessaire de reconstruire le code.

Une telle structure de partitions à l'avenir facilitera l'écriture d'un composant de mise à jour logicielle. Ce composant remplacera l'une des sections ROOT_1 / ROOT_2, qui n'est pas utilisée maintenant, puis modifiera simplement le fichier boot.txt si vous n'avez pas besoin de changer le noyau.

Choisir un chargeur de démarrage.

J'ai eu beaucoup d'expériences avec des bootloaders pour BBB. Au début, j'ai utilisé, comme tout le monde, le U-Boot généré par BuildRoot. Mais je n'aimais pas ça, peut-être, bien sûr, c'est une question d'habitude, mais il me semblait que c'était trop, c'est très lourd et difficile à configurer. Ensuite, j'ai pensé qu'il ne serait pas mauvais de démarrer le système rapidement, en 2-3 secondes, et de déposer le X-Loader pour qu'il charge le noyau, j'ai réussi, mais là encore il y avait un problème de configuration, et l'heure de départ pour moi pas critique (le système sur systemd démarre lentement par lui-même, même si vous supprimez tout ce qui n'est pas nécessaire).

Au final, je me suis installé sur barebox, j'ai beaucoup aimé sa simplicité, en plus le site a toute la documentation (www.barebox.org).

Par exemple, pour charger rootfs à partir de la première ou de la deuxième partition, il vous suffit de:

1. dans la section boot, faites le fichier boot.txt qui va exporter une variable de type "export BOOT_NUM = X"

2. créez deux scripts / env / boot / sdb1 / env / boot / sdb2 dans lesquels décrire les options de démarrage, par exemple:

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. créer un script / env / boot / sd dans lequel, en fonction de BOOT_NUM, démarrer le script sdb1 ou sdb2

4. définissez la variable boot.default

 nv boot.default=sd saveenv 

5. En modifiant encore BOOT_NUM dans boot.txt, nous chargerons rootfs à partir de la première ou de la deuxième partition, qui à l'avenir peut être utilisée pour la mise à jour logicielle.

Modifications apportées à l'arborescence des périphériques.

Puisque j'utilise MODBUS RTU via RS485 pour communiquer avec les modules, j'avais besoin d'activer presque tous les ports série qui existent sur le BBB. Pour ce faire, vous devez les réactiver dans l'arborescence des périphériques, car Par défaut, la plupart d'entre eux sont désactivés.

Il serait correct de créer votre correctif pour le fichier am335x-bone-common.dtsi à partir du package buildrut et de l'appliquer à chaque fois avant de l'assembler, mais la paresse a gagné, et j'ai simplement retiré tous les fichiers dont j'avais besoin, changé tout ce dont j'avais besoin et créé avec mes mains.

Parce que cela se fait une fois, c'est possible et donc:

1. Créez un dossier avec les fichiers nécessaires à l'assemblage:

 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. Dans le fichier am335x-bone-common.dtsi, vous devez configurer correctement les broches et désactiver les pilotes de port:

 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. Ensuite, un peu de magie, et le fichier fini am335x-boneblack.dtb se trouve dans le même répertoire:

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

b. exécutez le préprocesseur:

 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. exécutez le compilateur lui-même:

 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 doit être placé sur la partition de démarrage à côté du noyau et dans le script de démarrage de barebox, ajoutez la ligne suivante - " global.bootm.oftree=/boot/am335x-boneblack.dtb "

Choisir un système de collecte des débits négociés.

Comme vous le savez, les systèmes sans bugs n'existent pas, ainsi que l'analyse d'un système multi-thread sans traces. Il est très pratique que ces traces ne s'affichent pas simplement dans la console, mais soient collectées à l'aide de quelque chose de spécialement créé pour cela, afin qu'il soit possible de les trier par processus, d'appliquer des filtres, etc. Et je connais juste un bon système qui est facile à construire sous l'hôte et la cible. Il s'agit de DLT, si vous n'en avez jamais entendu parler, cela n'a pas d'importance, toutes les lacunes dans les connaissances peuvent être facilement comblées en lisant at.projects.genivi.org/wiki/display/PROJ/Diagnostic+Log+and+Trace .
Ce système se compose de dlt-daemon et dlt-viewer. Comme son nom l'indique, dlt-daemon s'exécute sur la cible et dlt-viewer sur l'hôte. De plus à tout cela, à votre binaire, à partir duquel nous voulons collecter des traces, vous devez lier la lib dlt.



En général, tout est pratique, comment collecter des traces et les analyser, je recommande.

Ecrire un système de build.

Pourquoi écrire un système de construction, car vous pouvez tout télécharger à partir des référentiels, le construire avec vos mains, construire sur la base de ces rootfs et de ce voile, le contrôleur fonctionne. Mais répéter une telle astuce en un mois sera plus difficile, et en deux - c'est généralement impossible. Encore une fois, vous devez vous rappeler quoi, où mettre, quoi construire et comment commencer. Par conséquent, après avoir passé beaucoup de temps au début, vous l'enregistrez plus tard, et vous avez la possibilité de créer facilement sous l'hôte et la cible. Le système de construction se compose d'un ensemble de scripts qui préparent d'abord l'hôte pour la construction, téléchargent des composants tiers, tels que buildroot, moustique, démon DLT, à partir de leurs référentiels, les construisent, les mettent à leur place. Et puis vous pouvez lancer la construction de votre projet. Si la construction sous l'hôte n'est pas difficile à faire, alors vous devez toujours bricoler la construction sous la cible, et ce serait mieux si le script le faisait.

Buildroot peut être configuré pour invoquer un script post-build après avoir formé rootfs, qui se trouvera dans buildroot / output / target. Cela vous donne une excellente occasion d'y mettre tout ce dont vous avez besoin. Et puis, l'image du système de fichiers contiendra déjà tout ce dont vous avez besoin pour démarrer votre système.

La recette est quelque chose comme ça:

  1. vous devez copier vos fichiers binaires quelque part dans buildroot / output / target, par exemple dans / opt / bin
  2. s'il y a des configurations, alors faites de même avec elles, uniquement dans / opt / etc
  3. copier des binaires tiers, pour moi c'est le moustique, le démon DLT, leurs libs et configs
  4. Afin de démarrer le système lui-même lors du chargement du contrôleur, vous devez copier vos services systemd, il est préférable de les combiner dans votre cible et de le réactiver en créant un lien symbolique en multi-utilisateurs.
  5. copier le fstab modifié (pourquoi, je vous le dirai plus tard)

Après cela, il vous suffit de décompresser buildroot / output / images / rootfs.tar vers la section souhaitée de la carte SD et de mettre sous tension.

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

Rédaction d'un noyau de communication.

Le concept est aussi ancien que le modbus lui-même.

Chaque périphérique d'E / S d'un réseau Modbus dispose de registres (16 bits) disponibles pour la lecture, la lecture / l'écriture, dans lesquels les données sont stockées et à travers lesquelles ces périphériques sont contrôlés. Le contrôleur, à son tour, dispose de tableaux de points discrets (état et valeur d'octet) et analogiques (état et valeur flottante), dans lesquels il stocke l'état de tous les paramètres.

Ainsi, la tâche du cœur de communication est simple: collecter des données à partir des périphériques d'E / S à l'aide du protocole Modbus, les mapper aux points du contrôleur et fournir un accès à ces points pour le niveau supérieur. Et si vous avez besoin de gérer quelque chose, alors tout est dans l'autre sens - le périphérique logique (plus à ce sujet plus tard) doit être abonné au point du contrôleur et l'écriture à ce point lance la traduction de ce paramètre vers le périphérique physique de sortie d'eau.



Afin de structurer les données et de travailler avec des appareils, vous pouvez introduire le concept d'un appareil logique qui affichera l'état d'un appareil physique dans votre logiciel.

J'ai également décidé de diviser les périphériques logiques en deux groupes:

  1. Standard (modules Bélier d'entrées / sorties discrètes), pour lesquels le nombre de registres Modbus avec des données est connu à l'avance, et il suffit juste de déterminer les points du contrôleur où enregistrer ces données.
  2. Les appareils utilisateurs, pour eux, il est nécessaire de décrire indépendamment le mappage des registres Modbus aux points du contrôleur.

De tout ce qui précède, il est logique d'avoir une sorte de configurateur pour le contrôleur, que ce soit juste une configuration json ou un outil auto-écrit générant une configuration binaire, tout convient. J'ai la deuxième option, car il y avait des idées pour écrire un noyau de communication afin qu'il puisse être facilement exécuté non seulement sur la carte Linux mais aussi sur Arduin avec FreeRtos, en changeant le niveau PAL dans le logiciel.

Dans le configurateur de chaque périphérique, vous devez définir le numéro de port du contrôleur rs485, l'adresse du périphérique et le point du contrôleur vers lequel l'état de la communication avec le périphérique est affiché, plus pour chaque périphérique standard ses canaux sont décrits, et pour un périphérique utilisateur, il est mappé sur des registres.





Un tel fichier de configuration, contenant toutes les données nécessaires à la construction du réseau Modbus, vous permet de ne pas modifier le code source du projet si vous avez besoin d'ajouter / supprimer / changer des périphériques d'entrée / sortie, il suffit de changer les paramètres dans le configurateur et de les enregistrer dans le fichier de configuration.

Au démarrage, le noyau de communication analyse la configuration et crée sur sa base des listes de périphériques logiques pour chaque port rs485 du contrôleur, puis des threads sont créés sur chaque port et une interrogation cyclique des périphériques physiques commence.

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

Écriture de la passerelle mqtt.

En fait - vos points de contrôleur, à la fois discrets et analogiques, avec une interface propriétaire pour y accéder, sont de peu d'intérêt pour personne. Il n'y a donc qu'une seule issue: mqtt. Je pense que je n'exagère pas si je dis que c'est actuellement le protocole le plus courant pour l'échange de petits messages, en plus il est très simple et compréhensible à utiliser. Donc, quand j'avais besoin de transmettre des données à partir du contrôleur - je ne pensais pas longtemps à quoi utiliser.



Parce que J'ai beaucoup de paramètres, puis il y avait toujours des confusions dans le fichier de configuration de la passerelle, où le mappage des points du contrôleur vers les sujets de la passerelle mqtt était enregistré. Google a aidé la table et écrit un analyseur csv de cette table dans le fichier de configuration json pour la passerelle.



passerelle git repo
parser git repo

Moniteur de point d'écriture.

Parfois, il est très utile de voir ce qui se passe avec les points du contrôleur, pour cela j'ai écrit une petite application qui se connecte directement au noyau de communication et lit l'état des points discrets et analogiques. Je suis assez proche de l'interface utilisateur, j'ai donc été en mesure de lancer l'application en QML, cela a fonctionné avec un craquement, vous pouvez compter le point, vous pouvez l'écrire, mais je n'en ai pas besoin de plus.

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

Montez le système de fichiers en lecture seule.

Habituellement, peu de gens y prêtent attention, et même dans les projets de production, vous pouvez trouver des périphériques dans lesquels la partition avec rootfs est accessible en écriture. Tôt ou tard, cela entraîne le crash de tout système de fichiers, même le plus stable. Parce que Étant donné que le contrôleur peut être éteint à tout moment, ce n'est qu'une question de temps / cas lorsque cela se produit. Pour minimiser cette probabilité, vous devez bricoler un peu avec fstab, et avant de construire l'image rootfs, placez-la comme décrit ci-dessus. Dans fstab, premièrement, vous devez monter le système de fichiers en lecture seule, et deuxièmement, tout ce qui peut changer peut être mappé dans tmpfs.

Mon fstab est le suivant, il peut différer pour vous:

 /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 

Corps du contrôleur

Une imprimante 3D a longtemps été incluse dans les sections de tête de mât pour chaque ingénieur agriculteur collectif, malheureusement je ne l'ai pas, mais elle est à l'œuvre. Récemment, l'excitation des autres employés pour lui a disparu, je l'utilise lors de l'impression de tout ce dont j'ai besoin et dont je n'ai pas besoin, vous pouvez en être convaincu en lisant mon post précédent.

Nous dessinons dans FreeCAD, nous générons le gcode dans Cura et nous obtenons un boîtier, sans oublier de faire des sièges pour la carte, des découpes pour les connecteurs et le refroidissement et des hypothèques pour les clips sur un rail DIN.





Eh bien, c’est tout, nous avons maintenant une carte, un logiciel sur une carte SD et un étui. Nous prenons un fichier (je ne plaisante pas) et connectons tout ensemble, connectons l'alimentation, les câbles RS485 et tout commence à fonctionner. Et tu as dit difficile, difficile ...

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


All Articles