<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="3.10.0">Jekyll</generator><link href="https://papsdroidfr.github.io//feed.xml" rel="self" type="application/atom+xml" /><link href="https://papsdroidfr.github.io//" rel="alternate" type="text/html" /><updated>2025-11-13T20:47:49+00:00</updated><id>https://papsdroidfr.github.io//feed.xml</id><title type="html">papsdroid</title><subtitle>tutoriels à base de Raspberry pi, Raspberry pico</subtitle><author><name>PapsDroid</name><email>papsdroid.fr@gmail.com</email></author><entry><title type="html">Stepper motor TMC</title><link href="https://papsdroidfr.github.io//tutoriels/pcb-motor-stepper/" rel="alternate" type="text/html" title="Stepper motor TMC" /><published>2025-11-10T00:00:00+00:00</published><updated>2025-11-10T00:00:00+00:00</updated><id>https://papsdroidfr.github.io//tutoriels/pcb-motor-stepper</id><content type="html" xml:base="https://papsdroidfr.github.io//tutoriels/pcb-motor-stepper/"><![CDATA[<p class="text-justify"><img src="/assets/images/tutos/044_1motor/pcb4_300.png" alt="Stepper" class="align-left" />
Cette carte permet de contrôler un moteur pas à pas à l’aide d’un TMC2208 ou TMC2209 avec comme software le système d’interface parallèle 16bits utilisé dans <a href="https://papsdroidfr.github.io/tutoriels/16bitsParallelControlCard/">ce projet de contrôle de 8 moteurs</a>. Le contrôle du moteur pour le faire avancer ou reculer à des vitesses précises passe par un fichier gcode, écrit en json.</p>

<h2 id="hardware">Hardware</h2>

<h3 id="matériel-nécessaire">Matériel nécessaire</h3>

<p>Il vous faut:</p>

<ul class="text-justify">
  <li>Un <strong>Raspberry PICO</strong>, version 1 ou 2 peu importe.</li>
</ul>
<ul class="text-justify">
  <li>Un moteur pas à pas 12v de type <strong>NEMA17</strong> (personnellement j’utilise  un modèle 17HE15-1504S)</li>
</ul>
<ul class="text-justify">
  <li>Un <strong>driver TMC2208 ou TMC2209</strong> qui va permettre de convertir les instructions en 3.3v envoyées par le microcontrôleur en 12v vers les bobines du moteur pas à pas. Ces drivers sont miniatures, efficaces et permettent un contrôle du moteur sans aucun bruit. La carte fonctionnera aussi avec un  driver A4988, mais ils sont dépassés, et bien moins efficaces que les drivers TMC.</li>
</ul>
<ul class="text-justify">
  <li>Une alimentation <strong>DC 12v 60Watts (5A)</strong> avec un connecteur Jack DC. Attention à ne pas prendre une alimentation 5v.</li>
</ul>
<ul class="text-justify">
  <li>1 <strong>micro-switch DIP</strong> avec 3 boutons, pour configurer les micro-steps de chaque moteur. Seuls les 2 premiers boutons sont utiles pour les drivers TMC (le troisième ne sert que pour les driver A4988).</li>
</ul>
<ul class="text-justify">
  <li>1 <strong>condensateur</strong> 25v 100uf, les plus petits en hauteur (il faut les loger sous les drivers TMC).</li>
</ul>
<ul class="text-justify">
  <li>1 <strong>led 5mm</strong> pour visualiser la mise sous tension de la carte (j’ai opté pour une led rouge).</li>
</ul>
<ul class="text-justify">
  <li>1 <strong>résistance</strong> 1/4watts de 220ohms (pour la led).</li>
</ul>
<ul class="text-justify">
  <li>1 convertisseur 12v-5v <strong>TRACO TSR</strong>: leur rendement est excellent (&gt;90%).</li>
</ul>
<ul class="text-justify">
  <li>1 connecteur <strong>JackDC</strong> à souder avec 3 pattes.</li>
</ul>
<ul class="text-justify">
  <li>2 <strong>pin header mâle 4 pins</strong> pour connecter le moteur et une interface i2c optionnelle (pour un écran OLED déporté).</li>
</ul>
<ul class="text-justify">
  <li>2 <strong>pins header femelles 8 pins</strong> afin d’y connecter le driver sans avoir à les souder sur la carte.</li>
</ul>
<ul class="text-justify">
  <li>2 <strong>pins headers femelles 20 pins</strong> afin d’y connecter le raspberry pico sans avoir à le souder sur la carte.</li>
</ul>
<ul class="text-justify">
  <li>bien entendu <strong>la carte PCB</strong> que vous pouvez re-faire fabriquer à partir des fichiers GERBER fournis dans <a href="https://github.com/papsdroidfr/pcb_1_stepper_motor">ce Github</a> dans le dossier <strong>PCB</strong>, ou bien vous pouvez me contacter pour voir s’il men reste en stock.</li>
</ul>

<h3 id="schéma-électronique">Schéma électronique</h3>

<figure class=" ">
  
    
      <a href="/assets/images/tutos/044_1motor/kicad_800.png" title="Schéma KICAD">
          <img src="/assets/images/tutos/044_1motor/kicad_600.png" alt="" />
      </a>
    
  
  
    <figcaption>Cliquez pour agrandir l’image.
</figcaption>
  
</figure>

<h3 id="assemblage-de-la-carte">Assemblage de la carte</h3>

<p class="text-justify"><img src="/assets/images/tutos/044_1motor/pcb1_600.png" alt="Stepper" class="align-center" />
Aucune difficulté, il ne faut pas se tromper de sens avec la soudure de la diode (Cathode matérialisée avec une petite barre horizontale à souder sur le K), de la led (patte la plus courte sur la masse), du condensateur (patte la plus courte sur la masse) et du convertisseur 12v-5v: la sérigraphie aide à se repérer. Connectez dans le bon sens aussi le Raspberry PICO (port usb dans la même direction que la prise Jack) et le driver TMC (vis de réglage vers l’extérieur de la carte), sinon ils seraient détruits dès la mise sous tension du système. Le micro-dip switch sérigraphié est en position OFF.</p>

<figure class="half ">
  
    
      <a href="/assets/images/tutos/044_1motor/pcb2_600.png" title="premières soudures">
          <img src="/assets/images/tutos/044_1motor/pcb2_300.png" alt="" />
      </a>
    
  
    
      <a href="/assets/images/tutos/044_1motor/pcb3_600.png" title="Montage final">
          <img src="/assets/images/tutos/044_1motor/pcb3_300.png" alt="" />
      </a>
    
  
  
    <figcaption>Cliquez pour agrandir les images
</figcaption>
  
</figure>

<p class="text-justify text-justify">Le moteur se branche sur les pin header localisés à côté de l’alimentation Jack DC.</p>

<h3 id="micro-stepping-du-moteur">Micro-stepping du moteur</h3>

<p class="text-justify">Le <strong>micro-stepping</strong> du moteur (full, 1/2pas, 1/4pas, 1/8pas etc …) est défini à l’aide du DIP micro-switch: 3 positions on/off sont nécessaires pour un A4988, mais seuls les 2 1er on/off seront nécessaires pour les TMC2208 et TMC2209. Suivez les instructions de votre driver pour paramétrer correctement le micro-stepping souhaité.</p>

<blockquote class="text-justify">
  <p><strong>Attention</strong>: ne pas modifier les positions des DIP-SWITCH lorsque le moteur est en train de fonctionner: il faut le faire hors tension.</p>
</blockquote>

<h3 id="boîtier-imprimé-3d">Boîtier imprimé 3D</h3>

<p><img src="/assets/images/tutos/044_1motor/boitier_600.png" alt="Stepper" class="align-center" /></p>

<p>Un boîtier minimaliste à imprimer en 3D est disponible dans la section <strong>/STL</strong> du <a href="https://github.com/papsdroidfr/pcb_1_stepper_motor">Github</a> du projet.</p>

<h2 id="software">Software</h2>

<p><img src="/assets/images/logos/github-flat-shadow-octocat-emblem-64.png" alt="Stepper" class="align-left" /> <a href="https://github.com/papsdroidfr/pcb_1_stepper_motor">Github</a> du projet.</p>

<h3 id="installation-bibliothèque">Installation bibliothèque</h3>

<p class="text-justify">Installez bien la dernière version MicroPython sur votre microcontrôleur. Cet <a href="https://papsdroidfr.github.io/configuration/pico/">article</a> détaille comment s’y prendre avec un Raspberry PICO.</p>

<p class="text-justify">Tout le code micropython est à récupérer sur le <a href="https://github.com/papsdroidfr/pcb_1_stepper_motor">Github du projet</a> dans la section <strong>micropython</strong>.</p>

<p class="text-justify">Tous les modules sont à uploader à la racine du PICO.</p>
<ul class="text-justify">
  <li><strong>/gcode</strong>: fichier gcode au format json</li>
</ul>
<ul class="text-justify">
  <li><strong>/sm</strong>: module de gestion de la machine à état qui gère l’interface parallèle 16bits.</li>
</ul>
<ul class="text-justify">
  <li><strong>/stepper</strong>: module qui gère le driver TMC (ou A4988).</li>
</ul>
<ul class="text-justify">
  <li><strong>main.py</strong>: progamme principal qui s’exécute au démarrage du système.</li>
</ul>

<h3 id="usage">Usage</h3>

<p class="text-justify">Le pilotage du moteur se fait grâce au fichier gcode déposé dans le dossier <strong>/gcode</strong>. Pour comprendre comment écrire un fichier gcode pour ce système, je vous encourage à lire la section <strong>fichier de trajetoire</strong> de <a href="https://papsdroidfr.github.io/tutoriels/16bitsParallelControlCard/#fichiers-de-trajectoires">cet article</a>.</p>

<p><img src="/assets/images/tutos/044_1motor/pcb_montage_600.jpg" alt="Stepper" class="align-center" /></p>]]></content><author><name>PapsDroid</name><email>papsdroid.fr@gmail.com</email></author><category term="tutoriels" /><category term="micro-python" /><category term="raspberry pico" /><category term="stepper-motor" /><category term="TMC2208" /><category term="TMC2209" /><summary type="html"><![CDATA[PCB pour contrôler un moteur pas à pas avec driver TMC]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://papsdroidfr.github.io//assets/images/tutos/044_1motor/pcb4_300.png" /><media:content medium="image" url="https://papsdroidfr.github.io//assets/images/tutos/044_1motor/pcb4_300.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Cryptomonnaie - Analyse Technique - Raspberry pi</title><link href="https://papsdroidfr.github.io//tutoriels/rascrypto/" rel="alternate" type="text/html" title="Cryptomonnaie - Analyse Technique - Raspberry pi" /><published>2025-07-04T00:00:00+00:00</published><updated>2025-07-04T00:00:00+00:00</updated><id>https://papsdroidfr.github.io//tutoriels/rascrypto</id><content type="html" xml:base="https://papsdroidfr.github.io//tutoriels/rascrypto/"><![CDATA[<p class="text-justify"><img src="/assets/images/tutos/043Rascrypto/rascrpyto_300.png" alt="rascrypto" class="align-left" />
Cet article détaille la procédure complète pour installer, configurer et exécuter l’application <strong>RasCrypto</strong>, un serveur local d’analyse technique sur la cryptomonnaie, hébergé sur un Raspberry pi4 avec au minimum 4Go de RAM. Ce projet fonctionnera parfaitement avec un Raspberry pi5, mais sera trop limité sur un pi3 car il faut manipuler d’importantes quantité de données.</p>

<h2 id="avertissement">Avertissement</h2>

<blockquote class="text-justify">
  <p>Ce projet et ce guide sont fournis à des fins purement éducatives. Ils ont pour but de montrer comment collecter des données de marché sur les crypto actifs, effectuer des calculs d’analyse technique et automatiser des tâches comme l’envoi de reports par e-mail avec Python sur un Raspberry Pi. Les informations et analyses générées par cette application ne constituent en aucun cas un conseil en investissement. L’investissement dans les cryptomonnaies est <strong>très risqué</strong> et vous devez faire vos propres recherches. L’auteur de ce projet et de ce guide ne saurait être tenu responsable de toute décision financière que vous prendriez.</p>
</blockquote>

<h2 id="résumé-fonctionnel-et-technique">Résumé Fonctionnel et Technique</h2>

<h3 id="résumé-fonctionnel">Résumé Fonctionnel</h3>

<p class="text-justify"><strong>RasCrypto</strong> est une application web locale conçue pour automatiser l’analyse technique de paires de cryptomonnaies (exple: BTCUSDC, ETHEUR …). Ses fonctionnalités principales sont :</p>

<ul class="text-justify">
  <li>
    <p><strong>Serveur web local</strong>: l’application se consulte via un navigateur web connecté au même réseau local: elle n’est pas ouverte sur l’extérieur.</p>
  </li>
  <li>
    <p><strong>Génération de graphiques</strong>: Elle crée des graphiques dynamiques en chandeliers (OHLCV - Open, High, Low, Close, Volume) pour visualiser l’évolution du cours d’une cryptomonnaie sur une période donnée (jour, semaine, mois, année(s)).</p>
  </li>
</ul>

<ul class="text-justify">
  <li><strong>Calcul d’indicateurs techniques</strong>: Sur ces graphiques, elle superpose plusieurs indicateurs clés de l’analyse technique :</li>
</ul>
<blockquote class="text-justify">
  <p><strong>Moyennes Mobiles</strong> (court terme et long terme)</p>
</blockquote>

<blockquote class="text-justify">
  <p><strong>Niveaux de Support et de Résistance</strong></p>
</blockquote>

<blockquote class="text-justify">
  <p><strong>RSI</strong> (Relative Strength Index)</p>
</blockquote>

<blockquote class="text-justify">
  <p><strong>MACD</strong> (Moving Average Convergence Divergence)</p>
</blockquote>

<ul class="text-justify">
  <li><strong>Reporting par email</strong>:  L’application peut envoyer automatiquement et de manière quotidienne, hebdomadaire ou mensuelle un rapport complet par email sur une paire de cryptomonnaie, incluant une analyse complète avec les graphiques en pièce jointe.</li>
</ul>

<ul class="text-justify">
  <li><strong>Monitoring</strong>: L’application permet de consulter la température interne du Raspberri pi, l’occupation des CPUs, RAM et espace Disque.</li>
</ul>

<ul class="text-justify">
  <li><strong>Automatisation</strong>: Le système est conçu pour être démarré automatiquement au démarrage du raspberry pi.</li>
</ul>

<figure class=" ">
  
    
      <a href="/assets/images/tutos/043Rascrypto/rascrpyto_1024.png" title="bashtop">
          <img src="/assets/images/tutos/043Rascrypto/rascrpyto_800.png" alt="" />
      </a>
    
  
  
    <figcaption>Cliquez pour agrandir l’image.
</figcaption>
  
</figure>

<h3 id="stack-technique">Stack Technique</h3>

<p class="text-justify"><strong>Langage</strong> : Python 3, avec une approche orientée objet pour structurer le code.</p>
<p class="text-justify"><strong>Framework Web</strong> : Flask, un framework web utilisé pour créer l’interface web de l’application.</p>
<p class="text-justify"><strong>Base de Données</strong> : SQLite, un moteur de base de données léger, utilisé pour stocker l’ordonnancement des reportings envoyés par e-mail.</p>
<p class="text-justify"><strong>Bibliothèques</strong> Python Principales :</p>

<ul class="text-justify">
  <li><strong>Flask</strong> pour gérer le front-end en python.</li>
</ul>
<ul class="text-justify">
  <li><strong>python-binance</strong> pour récupérer les données de marché des cryptomonnaies.</li>
</ul>
<ul class="text-justify">
  <li><strong>polars</strong> pour la manipulation et l’analyse des données.</li>
</ul>
<ul class="text-justify">
  <li><strong>plotly</strong> pour la génération de graphiques dynamiques</li>
</ul>
<ul class="text-justify">
  <li><strong>mplfinance</strong> pour la création des graphiques financiers attachés aux mails.</li>
</ul>
<ul class="text-justify">
  <li><strong>schedule</strong> pour gérer l’ordonnanceur de génération des rapports.</li>
</ul>

<h2 id="préparation-du-raspberry-pi">Préparation du Raspberry pi</h2>

<h3 id="installation-de-los-headless-64-bits">Installation de l’OS Headless 64-bits</h3>

<p class="text-justify">Ce serveur va fonctionner avec <a href="https://www.raspberrypi.com/software/">une version d’OS sans interface graphique</a> (Headless). A l’heure où j’écris et article, j’ai installé l’OS <strong>Raspberry PI OS Lite 64Bits</strong> à l’aide du software <strong>Rasbperry Pi Imager</strong> depuis mon ordinateur personnel qui fonctionne sous Linux Mint. J’ai configuré ma Box internet en DNS dynamique pour qu’elle attribue toujours la même adresse IP en local au Raspberry pi, que j’accède en SSH depuis mon ordinateur personnel pour installer et configurer l’application RasCrypto.</p>
<p class="text-justify">J’ai opté pour une configuration fanless avec un <a href="https://papsdroidfr.github.io/configuration/ArgonOneM2/">boîtier ArgonOne M2 et un disque SSD Nvme</a> pour installer le système: l’installation de l’OS, les reboots et redémarrages du Raspberry pi sont incomparablement plus rapides (reboot + démarrage en 10 secondes) qu’avec une carte SD. Le boîtier ArgonOne sert de refroidissement passif au CPU, il n’atteint jamais la température qui déclenche le petit ventilateur (constatation après 1 mois de fonctionnement h24 7j sur 7): c’est en cela que je le considère “fanless” alors qu’il y a bien un ventilateur pour le protéger au cas où les températures s’emballent.</p>

<p class="text-justify">Pour connaître <strong>l’adresse IP</strong> du Raspberry pi, utilisez cette commande et repérez dans la section wlan0 l’adresse inet qui ressemble à <strong>192.168.xx.yy</strong>: notez la dans un coin car le serveur WEB sera accessible à cette adresse (via le port 5000).</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>ifconfig
</code></pre></div></div>

<h3 id="installation-de-lapplication-rascrypto">Installation de l’Application RasCrypto</h3>

<h4 id="mise-à-jour-système">Mise à jour système</h4>

<p class="text-justify">Le système étant fraîchement installé, il faut d’abord le mettre à jour et en profiter pour installer les bibliothèques qui vont nous permettre de créer un environnement virtuel, afin de gagner un temps précieux pour installer toutes les dépendances de l’application.</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sudo </span>apt update
<span class="nb">sudo </span>apt full-upgrade <span class="nt">-y</span>
<span class="nb">sudo </span>apt <span class="nb">install</span> <span class="nt">-y</span> python3-pip python3-venv git
</code></pre></div></div>

<h4 id="création-dun-environnement-virtuel">Création d’un environnement virtuel</h4>

<p class="text-justify">Ces étapes doivent être réalisées depuis votre session SSH sur le Raspberry Pi. Nous allons installer le code <strong>dans le répertoire personnel</strong> de l’utilisateur (/home/pi/ si je prends comme hypothèse que vous avez opté pour un utilisateur ‘pi’).Il est crucial d’utiliser un environnement virtuel pour isoler les dépendances du projet.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># Assurez-vous d'être dans le répertoire personnel</span>
<span class="nb">cd</span> ~

<span class="c"># Créez l'environnement virtuel nommé .venv</span>
python3 <span class="nt">-m</span> venv .venv

<span class="c"># Activez l'environnement virtuel</span>
<span class="nb">source</span> .venv/bin/activate
</code></pre></div></div>

<blockquote class="text-justify">
  <p>Votre invite de commande devrait maintenant être préfixée par (.venv). <strong>Toutes les commandes suivantes doivent être exécutées avec l’environnement activé.</strong></p>
</blockquote>

<h4 id="clonage-du-code-depuis-github">Clonage du Code depuis GitHub</h4>
<p class="text-justify"><img src="/assets/images/logos/github-flat-shadow-octocat-emblem-64.png" alt="git" class="align-left" />
Clonez le dépôt Git directement dans votre répertoire personnel.</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># Assurez-vous d'être dans le répertoire personnel</span>
<span class="nb">cd</span> ~

<span class="c"># Clonez le projet</span>
git clone https://github.com/papsdroidfr/rascrypto.git
</code></pre></div></div>

<p class="text-justify">Ceci va créer un dossier <strong>/rascrypto</strong> contenant les sous-dossiers /cotation et /demo.</p>
<ul class="text-justify">
  <li>le dossier <strong>/rascrpyto/cotation</strong> contient tout le code de l’application RasCrypto.</li>
</ul>
<ul class="text-justify">
  <li>Le dossier <strong>/rascrypto/demo</strong> contient le code d’une démo d’un serveur Web local dont j’ai écrit <a href="https://papsdroidfr.github.io/dev/webserver/">cet article</a> si vous souhaitez voir un exemple simple de Serveur Web Local en Python avec Flask.</li>
</ul>

<h4 id="installation-des-dépendances">Installation des dépendances</h4>
<p class="text-justify">Grâce à l’environnement virtuel, l’installation de toutes les bibliothèques Python requises pour le projet est très simple:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># Déplacez-vous dans le répertoire du code</span>
<span class="nb">cd</span> ~/rascrypto/cotation

<span class="c"># Installez les paquets listés dans requirements.txt</span>
pip <span class="nb">install</span> <span class="nt">-r</span> requirements.txt
</code></pre></div></div>

<h4 id="configuration-de-lenvoi-demail">Configuration de l’envoi d’email</h4>

<p class="text-justify">L’application utilise un <strong>compte Gmail</strong> pour envoyer les rapports. Pour des raisons de sécurité, vous devez générer un mot de passe d’application spécifique.</p>

<p class="text-justify">Activer la <strong>validation en deux étapes</strong> : La création d’un mot de passe d’application requiert que la validation en deux étapes soit activée sur votre compte Google. Si ce n’est pas le cas, activez-la depuis les paramètres de sécurité de votre compte Google.</p>

<p><strong>Générer le mot de passe</strong> :</p>

<ul class="text-justify">
  <li>Allez sur la <a href="https://myaccount.google.com">page de gestion</a> de votre compte Google.</li>
</ul>
<ul class="text-justify">
  <li>Dans le menu de gauche, allez dans la section Sécurité.</li>
</ul>
<ul class="text-justify">
  <li>Descendez jusqu’à la section “Comment vous vous connectez à Google” et cliquez sur Mots de passe des applications. (Vous devrez peut-être vous reconnecter).</li>
</ul>
<ul class="text-justify">
  <li>Dans le menu déroulant “Sélectionner une application”, choisissez Autre (Nom personnalisé).</li>
</ul>
<ul class="text-justify">
  <li>Donnez-lui un nom explicite, par exemple RasCrypto, et cliquez sur GÉNÉRER.</li>
</ul>
<ul class="text-justify">
  <li>Un mot de passe de 16 caractères sera affiché. <strong>Copiez ce mot de passe immédiatement</strong>. Vous ne pourrez pas le revoir. C’est ce mot de passe que vous utiliserez dans le script, et non le mot de passe de votre compte Google.</li>
</ul>

<h4 id="configuration-du-script-de-démarrage">Configuration du script de démarrage</h4>

<p class="text-justify">Le script <strong>start.sh</strong> est le point d’entrée qui lance l’application. Vous devez le modifier pour y insérer vos informations personnelles. L’utilitaire nano va permettre de modifier ce fichier.</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>nano ~/rascrypto/cotation/start.sh
</code></pre></div></div>

<p class="text-justify">Modifiez les variables suivantes du fichier :</p>
<ul>
  <li><strong>export GMAIL_USER</strong>: Remplacez “MONEMAIL@GMAIL.COM” par votre adresse email Gmail qui va envoyer les rapports. Conservez bien les guilements.</li>
  <li><strong>export GMAIL_APP_PASS</strong>: Remplacez “MON PASSWORD APPPLICATIF GMAIL” par le mot de passe d’application de 16 caractères que vous venez de générer. conservez bien les guillemets.</li>
</ul>

<p class="text-justify">Ctrl O pour sauvegarder (puis ENTREE) et Ctrl X pour sortir de nano.</p>

<p class="text-justify">Rendez ensuite ce script <strong>exécutable</strong>:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">chmod</span> +x ~/rascrypto/cotation/start.sh
</code></pre></div></div>

<h4 id="configuration-de-lapplication">Configuration de l’application</h4>

<p class="text-justify">le fichier <strong>info.py</strong> contient les paramètres principaux de l’application que vous pouvez ajuster en utilisant nano comme précédemment.</p>

<ul class="text-justify">
  <li>TIME_SCHEDULEUR est l’heure à laquelle les reports sont générés et envoyés par e-mail.</li>
</ul>
<ul class="text-justify">
  <li>PERIOD_SHORT est le nombre de périodes pour le calcul de la moyenne mobile court terme.</li>
</ul>
<ul class="text-justify">
  <li>PERIOD_LONG est le nombre de périodes pour le calcul de la moyenne mobile long terme.</li>
</ul>
<ul class="text-justify">
  <li>PERIOD_SUPPORT est le nombre de périodes qui servent à calculer les niveaux de résistances et de support.</li>
</ul>
<ul class="text-justify">
  <li>CRYPTO est le dictionnaire des paires de cryptomonnaies que vous souhaitez suivre et qui vont apparaître dans le menu déroulant du dashboard principal de l’application.</li>
</ul>

<h4 id="intégration-dans-crontab">Intégration dans Crontab</h4>

<p class="text-justify">Pour un <strong>démarrage automatique</strong>, nous allons le préciser dans la crontab du Raspberry pi. Il faut aussi régulièrement rebooter le server, nous allons le programmer pour un reboot hebdomadaire (samedi à minuit)</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sudo </span>nano /etc/crontab <span class="nt">-e</span>
</code></pre></div></div>

<p class="text-justify">ajoutez ces 2 lignes à la fin (en supposant que ‘pi’ est l’utilisateur configuré sur le Raspberry pi):</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>@weekly root reboot
@reboot pi ~/rascrypto/cotation/start.sh &amp;
</code></pre></div></div>

<p class="text-justify">Ctrl O pour sauvegarder (puis ENTREE) et Ctrl X pour sortir de nano</p>

<blockquote class="text-justify">
  <p>L’application est maintenant configurée pour s’exécuter automatiquement à chaque redémarrage du Raspberry Pi. Le serveur va redémarrer tous les samedi à minuit.</p>
</blockquote>

<p class="text-justify">Pour redémarrer le Raspberry pi</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sudo </span>reboot
</code></pre></div></div>

<blockquote class="text-justify">
  <p>Il est important d’avoir noté l’adresse IP <strong>192.168.xx.yy</strong> du Raspberry pi et de s’assurer que votre Box internet vous attribuera toujours la même adresse IP. Le serveur WEB local généré par l’application RasCrypto est alors accessible sur le port 5000 depuis l’adresse http://192.168.xx.yy:5000, en vous connectant sur le même réseau que le Raspberry pi (non accessible en dehors de votre réseau local).</p>
</blockquote>

<blockquote class="text-justify">
  <p>Compte tenu de <strong>l’absence de sécurité</strong> mise en oeuvre pour protéger le réseau des menaces externes (il faudrait ajouter un serveur dédié pour la base de données, un serveur reverse proxy et un serveur WYSIWIG qui fait tampon avec le serveur applicatif, ainsi que protéger le mot de passe applicatif via un cryptage): je vous <strong>déconseille fortement</strong> de “bidouiller” ce projet pour le rendre accessible depuis l’extérieur. Il n’est pas du tout configuré pour, et vous exposeriez votre propre réseau interne à toutes les menaces du WEB où une grande majorité de bots malveillants viendraient repérer les failles de sécurité: ils se régaleraient dans ces conditions.</p>
</blockquote>

<h2 id="structure-logicielle-et-modèle-de-classes">Structure Logicielle et Modèle de Classes</h2>

<p class="text-justify">Le code est structuré de manière modulaire et orientée objet pour séparer les responsabilités.</p>

<h3 id="applpy">appl.py</h3>

<p class="text-justify">C’est le point d’entrée principal de l’application. Il contient la classe <strong>SiteWebLocal</strong> qui défini tout le front-end exécuté en tâche de fond, tandis que le thread principal faisant office de scheduler contrôle s’il faut générer et envoyer les reports par emails.</p>

<h3 id="cotationpy">cotation.py</h3>

<p class="text-justify">Contient la classe <strong>BinanceAPI</strong>. Elle va permettre de récupérer les données de marché.</p>

<ul class="text-justify">
  <li><strong>Responsabilité</strong> : Récupère les données brutes du marché pour une parie de cryptomonnaie (exple: BTCUSDC)</li>
</ul>
<ul class="text-justify">
  <li><strong>Méthodes</strong> : Elle contient une méthode qui récupère dans un dataframe polars l’historiques des données <strong>OHLCV</strong> (<strong>O</strong>pen price, <strong>H</strong>igh price, <strong>L</strong>ow price, <strong>C</strong>lose price, <strong>V</strong>olume) sur une profondeur d’historique donnée (start date) et des intervalles définis (exple 4h, 1h …)</li>
</ul>

<h3 id="analysispy">analysis.py</h3>

<p class="text-justify">Contient la classe <strong>TechnicalChartBuilder</strong>. C’est le cœur de l’analyse technique.</p>

<ul class="text-justify">
  <li><strong>Responsabilité</strong> : Construction d’analyses techniques modulaires</li>
</ul>
<ul class="text-justify">
  <li><strong>Méthodes</strong> : Elle contient les méthodes pour calculer tous les indicateurs techniques qui sont ajouté au dataframe polars qui contient l’historique des cours (statistiques de performance, moyennes mobiles, oscillateurs RSI et MACD, générateur de graphique exporté en png.)</li>
</ul>

<h3 id="emailerpy">emailer.py</h3>

<p class="text-justify">Contient la classe <strong>SimpleEmailer</strong> utilisée pour envoyer des emails avec pièces jointes.</p>

<ul class="text-justify">
  <li><strong>Responsabilité</strong> : Gérer l’envoi des emails.</li>
</ul>
<ul class="text-justify">
  <li><strong>Méthodes</strong> : fabrique le corps d’un email au format HTML et envoie l’email à un destinataire avec des images en pièce jointe.</li>
</ul>

<h3 id="scheduleurpy">scheduleur.py</h3>

<p class="text-justify">Contient la classe <strong>JobStore</strong> qui gère la base de données pour les tâches planifiées du scheduler.</p>

<ul class="text-justify">
  <li><strong>Responsabilité</strong> : Gérer les interactions avec la base de données SQLite.</li>
</ul>
<ul class="text-justify">
  <li><strong>Méthodes</strong> : Créer les tables si elles n’existent pas, insérer les nouvelles données de reports à produire, les lister et éventuellement les supprimer.</li>
</ul>

<h2 id="détail-des-analyses-techniques-proposées">Détail des Analyses Techniques Proposées</h2>

<p class="text-justify">L’application calcule et affiche plusieurs indicateurs d’analyse technique standards.</p>

<h3 id="statistiques-basiques">Statistiques basiques</h3>

<p class="text-justify">Pour une période choisie (par exemple 1 mois), l’application indique le cours de clôture à l’ouverture de la période, le cours de clôture à la fin de la période, la différence et la variation en %.</p>

<p><img src="/assets/images/tutos/043Rascrypto/stats.png" alt="rascrypto" class="align-center" /></p>

<h3 id="affichage-ohlcv">Affichage OHLCV</h3>

<p class="text-justify">Le graphique de base est un graphique en chandeliers japonais. Chaque “bougie” représente un intervalle qui dépend de la profondeur choisie (5mn pour 1 journée, 1h pour 1 semaine, 4h pour 1 mois, 1 jour pour 1an, 1 semaine pour 5 ans) et affiche 4 informations clés.</p>

<p><img src="/assets/images/tutos/043Rascrypto/chandeliers.png" alt="rascrypto" class="align-center" /></p>

<blockquote class="text-justify">
  <p>Open : Cours à l’ouverture de la période.</p>
</blockquote>
<blockquote class="text-justify">
  <p>High : Cours le plus haut de la période.</p>
</blockquote>
<blockquote class="text-justify">
  <p>Low : Cours le plus bas de la période.</p>
</blockquote>
<blockquote class="text-justify">
  <p>Close : Cours à la clôture de la période.</p>
</blockquote>
<blockquote class="text-justify">
  <p>Le volume des transactions de chaque période est affiché sous forme d’histogramme en bas du graphique.</p>
</blockquote>

<p class="text-justify">Pour un confort de lecture, les chandelles sont vertes quand le cours progresse (close &gt; open) et rouge dans le cas contraire, bien que l’information soit visible sur le graphique sans les couleurs.</p>

<h3 id="moyennes-mobiles">Moyennes Mobiles</h3>

<p class="text-justify">Il s’agit d’indicateurs de tendance. Une moyenne mobile lisse les données de prix pour identifier la direction de la tendance. Une moyenne mobile sur N périodes est la moyenne du cours de clôture des N dernières périodes.</p>
<p class="text-justify">L’application calcule et affiche deux moyennes mobiles :</p>

<ul class="text-justify">
  <li>Une courte (ex: 7 périodes) pour la tendance à court terme.</li>
</ul>
<ul class="text-justify">
  <li>Une longue (ex: 20 périodes) pour la tendance de fond.</li>
</ul>

<p><img src="/assets/images/tutos/043Rascrypto/moyenne-mobile.png" alt="rascrypto" class="align-center" /></p>

<h3 id="supports-et-résistances">Supports et Résistances</h3>

<p class="text-justify">Ces niveaux sont des “planchers” (supports) et des “plafonds” (résistances) psychologiques où les prix ont tendance à stagner ou à rebondir. L’application identifie ces niveaux en détectant les points bas (minima locaux) et les points hauts (maxima locaux) significatifs sur une période donnée. Ils sont matérialisés par des lignes horizontales sur le graphique (en haut et en rouge on trouve les résistances, en bas en vert on retrouve les supports).</p>

<p><img src="/assets/images/tutos/043Rascrypto/supports.png" alt="rascrypto" class="align-center" /></p>

<h3 id="rsi-relative-strength-index">RSI (Relative Strength Index)</h3>

<p class="text-justify">Il s’agit d’un indicateur de prédiction. C’est un oscillateur qui mesure la force et la vitesse des mouvements de prix. Il compare l’ampleur des hausses récentes à celle des baisses récentes. Le résultat est un indice oscillant entre 0 et 100. Un RSI au-dessus de 70 est souvent considéré comme un signal de “sur-achat” (le prix a monté trop vite), tandis qu’un RSI en dessous de 30 est considéré comme un signal de “sur-vente”. Les prix ont tendance à changer de direction dans ces cas.</p>

<p><img src="/assets/images/tutos/043Rascrypto/rsi.png" alt="rascrypto" class="align-center" /></p>

<p class="text-justify">Cet indicateur est positionné en dessous du graphe avec les chandeliers, sur la même échelle de temps.</p>

<h3 id="macd-moving-average-convergence-divergence">MACD (Moving Average Convergence Divergence)</h3>

<p class="text-justify">C’est encore un indicateur de prédiction de type oscillateur. Il montre la relation entre deux moyennes mobiles exponentielles (MME) du prix. Une moyenne mobile exponentielle va faire un calcul de moyenne pondérée au lieu de faire la moyenne des cours sur une période. Le MACD est calculé en soustrayant la MME longue (ex: 26 jours) de la MME courte (ex: 12 jours). Une “ligne de signal”, qui est une MME du MACD lui-même (ex: 9 jours), est également tracée.</p>

<p><img src="/assets/images/tutos/043Rascrypto/MACD.png" alt="rascrypto" class="align-center" /></p>

<p class="text-justify">L’histogramme du MACD (la différence entre les deux lignes) visualise l’élan de la tendance, tandis que le croisement de la ligne MACD avec sa ligne de signal peut prédire une forte probabilité à un retournement de situation.</p>

<h3 id="bandes-de-bollinger">Bandes de Bollinger</h3>

<p class="text-justify">Les bandes de Bollinger permettent de visualiser la volatilité de l’actif. Elles sont constituées de 3 courbes: une moyenne mobile sur N périodes et deux courbes situées de part et d’autre de la moyenne mobile, chacune étant située à 2 fois l’écart type sur les N périodes qui ont servies à calculer la moyenne mobile. Si on admet que l’actif suit une loi normale, 95% des valeurs observées restent à l’intérieur des bandes de Bollinger.</p>

<p><img src="/assets/images/tutos/043Rascrypto/bollinger.png" alt="rascrypto" class="align-center" /></p>

<h2 id="reporting-automatiques-par-e-mail">Reporting automatiques par e-mail</h2>

<p class="text-justify">L’application permet de planifier des envois de reports par e-mail tous les jours, toutes les semaines, tous les mois. Il suffit de s’abonner à un topic de l’onglet “Planification Emails” en précisant la paire de cryptomonnaie et la fréquence souhaitée.</p>

<p><img src="/assets/images/tutos/043Rascrypto/reports.png" alt="rascrypto" class="align-center" /></p>

<blockquote class="text-justify">
  <p>à ce jour j’ai codé un report unique quelque soit la fréquence choisie (je ferai un update plus tard): le report génère une analyse technique sur un mois, et une autre sur une semaine, regroupant les 2 analyses dans un seul mail.</p>
</blockquote>

<p><img src="/assets/images/tutos/043Rascrypto/mail30j.png" alt="rascrypto" class="align-center" />
<img src="/assets/images/tutos/043Rascrypto/mail7j.png" alt="rascrypto" class="align-center" /></p>

<blockquote class="text-justify">
  <p>Et en plus il est poli!</p>
</blockquote>

<h2 id="monitoring-serveur">Monitoring serveur</h2>

<p class="text-justify">Enfin dernière touche personnelle sur ce serveur: une page de monitoring de la température interne, utilisation de la RAM, utilisation des CPU et espace disque. Les données sont rafraîchies toutes les 5 secondes.</p>

<p><img src="/assets/images/tutos/043Rascrypto/monitoring.png" alt="rascrypto" class="align-center" /></p>

<blockquote class="text-justify">
  <p>Cet monitoring “temps réel” ne permet pas de voir ce qu’il se passe avec la RAM et les CPU lorsque le dashboard calcule et affiche les analyses techniques. Une évolution consisterai à sauvegarder en base de données les captures pour les afficher ensuite sous forme de graphe sur cette page. Cependant les calculs sont très rapides en polars, il faudrait capter les données plusieurs fois par secondes ce qui alourdirai à mon humble avis le travail de ce serveur. En attendant, vous pouvez aller regarder via ‘htop’ ce qu’il se passe en vous connectant en SSH sur le Raspberry pi.</p>
</blockquote>]]></content><author><name>PapsDroid</name><email>papsdroid.fr@gmail.com</email></author><category term="tutoriels" /><category term="python3" /><category term="raspberry pi" /><category term="web server" /><category term="cryptomonnaie" /><category term="Flask" /><summary type="html"><![CDATA[Web Server d'analyse technique de cours de cryptomonnaie]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://papsdroidfr.github.io//assets/images/tutos/043Rascrypto/rascrpyto_300.png" /><media:content medium="image" url="https://papsdroidfr.github.io//assets/images/tutos/043Rascrypto/rascrpyto_300.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Web Server Python et Flask</title><link href="https://papsdroidfr.github.io//dev/webserver/" rel="alternate" type="text/html" title="Web Server Python et Flask" /><published>2025-06-11T00:00:00+00:00</published><updated>2025-06-11T00:00:00+00:00</updated><id>https://papsdroidfr.github.io//dev/webserver</id><content type="html" xml:base="https://papsdroidfr.github.io//dev/webserver/"><![CDATA[<p class="text-justify"><img src="/assets/images/tutos/042WebServer/python_flask_300.jpg" alt="webserver" class="align-left" />
Cet article détaille comment monter un <strong>server web local</strong> sur un <strong>raspberry pi</strong> en moins de <strong>5mn</strong>, avec Python et Flask. Ce serveur ne sera pas ouvert à l’extérieur, donc on va aller au plus simple niveau architecture: pas de reverse proxy, pas de serveur de réplication WYSIWIG et pas de serveur de base de données: tout va tenir sur un seul Raspberry pi. L’objectif est de pouvoir consulter depuis son smartphone ou un ordinateur connecté au même réseau local les services de ce serveur web.</p>

<h2 id="hardware">Hardware</h2>

<p class="text-justify">Un simple raspberry pi avec une connectivité wifi ou réseau est nécessaire. Dans mon cas je suis parti avec un <a href="https://papsdroidfr.github.io/configuration/argon-one/">Raspberry pi4 8Go dans un boîtier Argon One</a> où le système est installé sur un SSD M.2 nvme de 128Go. Cette configuration me permet de bénéficier d’une solution fanless. Une sd card de 32Go est largement suffisante mais l’installation et le démarrage du système est beaucoup plus rapide avec un ssd M.2 nvme. J’ai utilisé l’OS LITE 64bit Raspberry pi OS car je n’ai pas besoin d’interface graphique.</p>

<h2 id="software">Software</h2>

<h3 id="structure">Structure</h3>
<p><img src="/assets/images/tutos/042WebServer/structure_640.png" alt="webserver" class="align-center" /></p>

<p class="text-justify">La structure du code minimale pour notre server web est la suivante:</p>

<ul class="text-justify">
  <li>Le programme principal <strong>demo.py</strong> à la racine.</li>
</ul>
<ul class="text-justify">
  <li>Les dépendances à installer si vous passez par un <a href="https://docs.python.org/fr/3.9/library/venv.html">environnement virtuel</a>: <strong>requirements.txt</strong>.</li>
</ul>
<ul class="text-justify">
  <li>Un dossier <strong>/static</strong> dans lequel figure le dossier <strong>/css</strong> avec les styles de nos pages.</li>
</ul>
<ul class="text-justify">
  <li>Un dossier <strong>/templates</strong> dans lequel figurent les pages html du site.</li>
</ul>

<h3 id="installation">Installation</h3>

<p class="text-justify"><img src="/assets/images/logos/github-flat-shadow-octocat-emblem-64.png" alt="webserver" class="align-left" />
Tout le code démo est à récupérer sur mon <a href="https://github.com/papsdroidfr/rascrypto">Github</a>, dans le dossier <strong>/demo</strong></p>

<p>Déposez tous les fichiers du répertoire <strong>/demo</strong> en respectant bien la structure décrite ci-dessus.</p>

<p class="text-justify">Si vous n’utilisez pas d’environnement virtuel (venv), il faut installer la bibliothèque Flask.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>pip <span class="nb">install </span>Flask
</code></pre></div></div>

<p class="text-justify">Sinon, il suffit d’installer les dépendances du requirements.txt:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>pip <span class="nb">install</span> <span class="nt">-r</span> requirements.txt
</code></pre></div></div>

<h3 id="usage">Usage</h3>

<p class="text-justify">pour démarrer le serveur WEB, rien de plus simple, il suffit d’exécuter le programme <strong>demo.py</strong></p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">python</span> <span class="n">demo</span><span class="p">.</span><span class="n">py</span>
</code></pre></div></div>

<p class="text-justify">Le site WEB est alors accessible en local sous l’adresse <strong>http://127.0.0.1:5000</strong></p>

<p><img src="/assets/images/tutos/042WebServer/demo_640.png" alt="webserver" class="align-center" /></p>

<p class="text-justify">Un bashtop montre que cette configuration n’occupe que 1Go de RAM et 12% de CPU (sachant que bashtop perturbe bien la mesure)</p>

<figure class=" ">
  
    
      <a href="/assets/images/tutos/042WebServer/bashtop_1024.png" title="bashtop">
          <img src="/assets/images/tutos/042WebServer/bashtop_640.png" alt="" />
      </a>
    
  
  
    <figcaption>Cliquez pour agrandir l’image.
</figcaption>
  
</figure>]]></content><author><name>PapsDroid</name><email>papsdroid.fr@gmail.com</email></author><category term="DEV" /><category term="python3" /><category term="raspberry pi" /><category term="web server" /><category term="Flask" /><summary type="html"><![CDATA[Structure d'un web server écrit en Python et Flask]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://papsdroidfr.github.io//assets/images/tutos/042WebServer/python_flask_300.jpg" /><media:content medium="image" url="https://papsdroidfr.github.io//assets/images/tutos/042WebServer/python_flask_300.jpg" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Interface parallèle 16bits pour 8 moteurs pas à pas.</title><link href="https://papsdroidfr.github.io//tutoriels/16bitsParallelControlCard/" rel="alternate" type="text/html" title="Interface parallèle 16bits pour 8 moteurs pas à pas." /><published>2025-03-05T00:00:00+00:00</published><updated>2025-03-05T00:00:00+00:00</updated><id>https://papsdroidfr.github.io//tutoriels/16bitsParallelControlCard</id><content type="html" xml:base="https://papsdroidfr.github.io//tutoriels/16bitsParallelControlCard/"><![CDATA[<p class="text-justify"><img src="/assets/images/tutos/04116bitsParallelCard/carte_300.jpg" alt="16bits" class="align-left" />
Cette carte est une <strong>interface parallèle 16bits</strong> qui peut piloter jusqu’à <strong>8 moteurs pas à pas</strong> (Stepper Motor) en mode step/dir à l’aide d’un <strong>fichier de trajectoires pré-calculées</strong> (GCode file) au format json. Les moteurs peuvent être drivés avec au choix des <strong>A4988</strong> (bruyants et dépassés), ou mieux avec des <strong>TMC2208</strong> ou <strong>TMC2209</strong> qu’il faudra configurer en mode step/dir et non pas UART. L’interface parallèle est gérée par une machine à état hébergée sur un <strong>Raspberry-pico</strong>. Elle va servir à animer <strong>un automate</strong> nécessitant jusqu’à 8 moteurs.</p>

<h2 id="hardware">Hardware</h2>

<h3 id="matériel-nécessaire">Matériel nécessaire</h3>

<p>Il vous faut:</p>

<ul class="text-justify">
  <li>1 <strong>Raspberry PICO</strong>, toutes les versions 1 ou 2 sont compatibles.</li>
</ul>
<ul class="text-justify">
  <li>1 petite <strong>diode Schottky</strong> 5v 1A, au format DO-41.</li>
  <li>1 à 8 moteurs pas à pas <strong>12v</strong> de type <strong>NEMA17</strong> (j’utilise  des modèles NEMA17HE15-1504S)</li>
</ul>
<ul class="text-justify">
  <li>1 à 8 <strong>drivers</strong> de moteurs A4988(je ne recommande pas: ils sont très bruyants et peu fiables), ou bien <strong>TMC2208</strong> en mode step/dir ou encore <strong>TMC2209</strong> en mode step/dir. <strong>Attention</strong> à ne pas prendre des TMC2208 ou TMC2209 en mode UART: ils ne sont pas compatibles avec cette carte.</li>
</ul>
<ul class="text-justify">
  <li>Une alimentation <strong>DC 12v</strong> de 360 Watts si vous comptez utiliser 8 moteurs.</li>
</ul>
<ul class="text-justify">
  <li>1 à 8 <strong>micro-switch DIP</strong> avec 3 boutons, pour configurer les micro-steps de chaque moteur.</li>
</ul>
<ul class="text-justify">
  <li>9 <strong>condensateurs</strong> 25v 100uf, les plus petits en hauteur (il faut les loger sous les drivers TMC)</li>
</ul>
<ul class="text-justify">
  <li>1 <strong>led 5mm</strong> pour visualiser la mise sous tension de la carte (j’ai opté pour une led rouge)</li>
</ul>
<ul class="text-justify">
  <li>1 <strong>résistance</strong> 1/4watts de 220ohms (pour la led)</li>
</ul>
<ul class="text-justify">
  <li>1 convertisseur 12v-5v <strong>TRACO TSR</strong>: leur rendement est excellent.</li>
</ul>
<ul class="text-justify">
  <li>1 connecteur mâle 12v <strong>XT60</strong></li>
</ul>
<ul class="text-justify">
  <li>1 <strong>pin header mâle 4 pins</strong> pour connecter l’interface i2c (pour un écran OLED déporté)</li>
</ul>
<ul class="text-justify">
  <li>1 <strong>pin header mâle 2 pins</strong> pour connecter un ventilateur 12v</li>
</ul>
<ul class="text-justify">
  <li>1 à 8 <strong>connecteurs mâles 4 pins</strong> pour brancher les moteurs</li>
</ul>
<ul class="text-justify">
  <li>1 connecteur <strong>JST mâle 3 pins</strong> pour brancher une interface UART</li>
</ul>
<ul class="text-justify">
  <li>2 à 16 <strong>pins header femelles 8 pins</strong> afin d’y connecter les 1 à 8 drivers sans avoir à les souder sur la carte.</li>
</ul>
<ul class="text-justify">
  <li>2 <strong>pins headers femelles 20 pins</strong> afin d’un connecter le raspberry pico sans avoir à le souder sur la carte.</li>
</ul>
<ul class="text-justify">
  <li>1 ventilateur 12v 60mm: je recommande un <strong>Noctua NF-A6x15 FLX</strong> car il est très silencieux.</li>
  <li>bien entendu <strong>la carte PCB</strong> que vous pouvez re-faire fabriquer à partir des fichiers GERBER fournis dans <a href="https://github.com/papsdroidfr/Stepper16bitsControl">ce Github</a> dans le dossier <strong>hardware</strong>, ou bien vous pouvez me contacter pour voir s’il men reste en stock.</li>
</ul>

<h3 id="assemblage-de-la-carte">Assemblage de la carte</h3>

<p class="text-justify"><img src="/assets/images/tutos/04116bitsParallelCard/PCB_800.jpg" alt="16bits" class="align-center" />
Si j’ai bien compté, il y a 333 soudures à faire sur cette carte. Les sérigraphies sont assez claires, il faut juste veiller à bien souder les condensateurs dans le bon sens (la patte la plus longue sur le +), ainsi que la led (idem patte la plus longue sur le +) et la diode Schottky dont la cathode est sérigraphiée sur le PCB. Les switch DIP doivent aussi être soudés comme indiqués sur la sérigraphie (“On” vers le “1”).</p>

<p class="text-justify"><img src="/assets/images/tutos/04116bitsParallelCard/PCB_soudures_800.jpg" alt="16bits" class="align-center" />
Pour souder les pins header femelle, je conseille vivement de les souder par paire avec les driver en place (idem pour les pins header femelle du Raspberry-PICO à souder avec le PICO en place): ceci afin de les souder bien droits.</p>

<figure class=" ">
  
    
      <a href="/assets/images/tutos/04116bitsParallelCard/PCB_montage_1024.jpg" title="PCB assemblé.">
          <img src="/assets/images/tutos/04116bitsParallelCard/PCB_montage_800.jpg" alt="" />
      </a>
    
  
  
    <figcaption>Cliquez pour agrandir l’image.
</figcaption>
  
</figure>

<p class="text-justify">Placez ensuite le Raspberry-pico dans le sens indiqué par la sérigraphie (prise usb vers le haut). Les drivers sont tous orientés dans le même sens, avec la petite vis de réglage vers la gauche comme sur la photo.</p>

<h3 id="impression-3d-boîtier">Impression 3D boîtier</h3>

<p class="text-justify"><img src="/assets/images/tutos/04116bitsParallelCard/boitier3D_300.png" alt="16bits" class="align-left" />
Un boîtier à imprimer 3D est à disposition dans le <a href="https://github.com/papsdroidfr/Stepper16bitsControl">Github du projet</a> dans le dossier <strong>3D_STL</strong>.
Il y a une partie basse dans laquelle la carte se loge, et une partie haute qui permet de maintenir en place le ventilateur et le passage des câbles (alimentation 12v et moteurs). La partie haute est à imprimer à l’envers: face haute vers le bas, pour éviter de faire trop de supports.</p>
<p><img src="/assets/images/tutos/04116bitsParallelCard/boitier3D_600.png" alt="16bits" class="align-center" /></p>

<h3 id="connection-des-moteurs">Connection des moteurs</h3>

<p><img src="/assets/images/tutos/04116bitsParallelCard/NEMA17_600.png" alt="16bits" class="align-center" /></p>

<p class="text-justify">J’ai pris en référence un <strong>NEMA17HE15</strong> qui a un connecteur 4 fils de 4 couleurs (Noir, Vert, Bleu, Rouge) avec 4 références qu’on retrouve sur chaque connecteur sérigraphié sur la carte (A+, B+, A-, B-). Si les branchements ne sont pas respectés en fonction du moteur choisi, il va vibrer au lieu de tourner correctement.</p>
<ul>
  <li>Noir: A+,</li>
  <li>Vert: B+,</li>
  <li>Bleu: A-,</li>
  <li>Rouge: B-</li>
</ul>

<blockquote class="text-justify">
  <p><strong>Attention</strong> les moteurs doivent se brancher ou débrancher uniquement lorsque la carte est <strong>hors tension</strong>, sinon vous risquez de les détruire ainsi que les drivers.</p>
</blockquote>

<p class="text-justify">Chaque moteur sur la carte est sérigraphié de <strong>M0</strong> à <strong>M7</strong>.</p>

<p class="text-justify">Pour brancher le ventilateur il suffit de brancher les 2 fils +12v et Gnd sur l’emplacement adéquat sur la carte. Si vous avez un ventilateur 3 fils comme avec le <strong>Noctua NF A6-X15</strong>, repérez bien le fil rouge (+12v) et le fil noir (Gnd). Quand au fil jaune qui sert à mesurer la vitesse du ventilateur: vous pouvez le laisser débranché, la carte ne l’exploite pas.</p>

<h3 id="micro-stepping-des-moteurs">Micro-stepping des moteurs</h3>

<p class="text-justify">Le <strong>micro-stepping</strong> de chaque moteur (full, 1/2pas, 1/4pas, 1/8pas etc …) est défini à l’aide des DIP micro-switch: 3 positions on/off sont nécessaires pour un A4988, mais seuls les 2 1er on/off seront nécessaires pour les TMC2208 et TMC2209. Suivez les instructions de votre driver pour paramétrer correctement le micro-stepping souhaité.</p>

<blockquote class="text-justify">
  <p><strong>Attention</strong>: ne pas modifier les positions des DIP-SWITCH lorsque les moteurs sont en train de fonctionner: il faut le faire hors tension.</p>
</blockquote>

<h2 id="software">Software</h2>

<p class="text-justify">Le firmware de la carte en <strong>micro-python</strong> est conçu pour fonctionner avec un <strong>Raspberry PICO</strong>, version 1 ou 2 peut importe. L’interface parallèle 16 bits est gérée par une machine à état.</p>

<h3 id="micro-python">Micro-python</h3>

<p class="text-justify">Si vous installez <strong>micro-python</strong> pour la première fois sur un <strong>Raspberry PICO</strong>, <a href="https://papsdroidfr.github.io/configuration/pico/">cet article</a> en résume les étapes.</p>

<h3 id="firmware">Firmware</h3>

<p class="text-justify">Le firmware écrit en <strong>micro-python</strong> est à récupérer sur le <a href="https://github.com/papsdroidfr/Stepper16bitsControl">Github du projet</a> dans la section <strong>software</strong>. Il faut bien veiller à récupérer tous les modules.</p>

<ul class="text-justify">
  <li><strong>gcode</strong>: contient les fichiers de trajectoire en exemple, au format json.</li>
</ul>
<ul class="text-justify">
  <li><strong>sm</strong>: module qui gère la machine à état pour l’interface parallèle 16 bits.</li>
</ul>
<ul class="text-justify">
  <li><strong>stepper</strong>: module de gestion des drivers.</li>
</ul>
<ul class="text-justify">
  <li><strong>main_automat.py</strong>: programme principal qui lance une animation parmi les fichiers de trajectoires qu’il y a sur la carte. Pour une exécution automatique au branchement de la carte, il suffit de <strong>renommer ce fichier en main.py</strong>. Sinon il faudra relier le Raspberry PICO à l’ordinateur via la prise USB pour démarrer le programme.</li>
</ul>

<h2 id="manuel-dutilisation">Manuel d’utilisation</h2>

<h3 id="fichiers-de-trajectoires">Fichiers de trajectoires</h3>

<p class="text-justify">Pour animer un automate avec 8 moteurs max, il faut préparer un <strong>fichier de trajectoires</strong> pré-calculées au format <strong>json</strong> à déposer dans le dossier <strong>/gcode</strong> sur le microcontrôleur. Ce fichier json a la structure suivante:</p>
<ul class="text-justify">
  <li><strong>“COMMENT”</strong>: ligne de commentaire</li>
</ul>
<ul class="text-justify">
  <li><strong>“DRIVER”</strong>: il faut préciser ici les drivers utilisés entre A4988, TMC2208 ou TMC2209</li>
</ul>
<ul class="text-justify">
  <li><strong>“FREQ-SM”</strong>: il s’agit de la fréquence de fonctionnement en Hz de la machine à état. Plus elle est élevée (exemple 700 Khz), et plus les moteurs vont tourner vite. Si vous dépassez 1Mhz (voire 600KhZ pour des A4988) ça ira trop vite les moteurs ne pourront pas suivre la cadence.</li>
</ul>
<ul class="text-justify">
  <li><strong>“MODE”</strong>: il faut indiquer LOOP ou UNIQUE selon qu’on veut rejouer l’animation en boucle ou pas.</li>
</ul>
<ul class="text-justify">
  <li><strong>“GCODE_SEQ”</strong>: on retrouve ici l’animation à jouer pour chaque moteur numéroté de 0 à 7.</li>
</ul>

<p class="text-justify">Pour un moteur donné, une animation consiste en une liste d’ordres qui sont exécutés les uns après les autres. Chaque ordre de chaque moteur est synchronisé au cycle d’horloge près par l’interface parallèle. Un ordre est une chaîne de caractères qui doit respecter ce pattern: ax_sn_dy_vz où x, n ,y et z sont des entiers:</p>

<ul class="text-justify">
  <li><strong>a</strong> représente l’action: x vaut 1 ou 0. 1 signifie au moteur d’avancer, 0 signifie de stopper.</li>
</ul>
<ul class="text-justify">
  <li><strong>s</strong> représente le nombre de steps: n est le nombre de steps où le moteur doit tourner (si x=1) ou le nombre de steps où il doit rester immobile (si x=0)</li>
</ul>
<ul class="text-justify">
  <li><strong>d</strong> représente la direction de rotation du moteur: y vaut 1 pour le sens horaire, 0 pour le sens anti-horaire.</li>
</ul>
<ul class="text-justify">
  <li><strong>v</strong> représente la vitesse de rotation. Dans ce mode le moteur bouge d’un step et marque un arrêt de z steps. Ainsi z=0 correspond à la vitesse maximale, tandis que z=1 fera tourner le moteur 2 fois plus lentement (1 step sur 2 il ne bouge pas), … , z=n fera tourner le moteur (n+1) fois plus lentement que z=0.</li>
</ul>

<p><strong>Exemples</strong>:</p>

<ul class="text-justify">
  <li>a1_s400_d1_v0: le moteur tourne de 400 steps dans le sens horaire, vitesse maximale.</li>
</ul>
<ul class="text-justify">
  <li>a0_S400_d1_v0: le moteur s’arrête pendant 400 steps dans le sens horaire, vitesse maximale: cet arrêt va durer exactement le même temps que s’il tournait de 400 steps dans le sens horaire à vitesse maximale.</li>
</ul>
<ul>
  <li>a1_s300_d0_v2: le moteur fonctionne 300 steps dans le sens anti-horaire à la vitesse 2 (il bouge 1 step et marque un arrêt de 2 steps).</li>
</ul>

<h3 id="exécution-dun-fichier-de-trajectoires">exécution d’un fichier de trajectoires</h3>

<p class="text-justify">Rien de plus simple, il suffit d’instancier un objet <strong>Automat</strong> en précisant le fichier gcode à utiliser:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">appl</span> <span class="o">=</span> <span class="n">Automat</span><span class="p">(</span><span class="n">gcode_file</span><span class="o">=</span><span class="s">'gcode/test_automat.json'</span><span class="p">)</span>
</code></pre></div></div>

<h2 id="evolution-en-cours">Evolution en cours</h2>

<p class="text-justify">Les évolutions suivantes sont en cours de réalisation:</p>

<ul class="text-justify">
  <li><strong>Interface WEB</strong> pour piloter la carte depuis son smart phone. Il faudra utiliser un Raspberry pico 1 ou 2 en version W.</li>
</ul>
<ul class="text-justify">
  <li><strong>Interface UARt</strong> pour communiquer le fichier de trajectoires en série, depuis une autre machine.</li>
</ul>]]></content><author><name>PapsDroid</name><email>papsdroid.fr@gmail.com</email></author><category term="tutoriels" /><category term="micro-python" /><category term="raspberry pico" /><category term="stepper-motor" /><category term="TMC2208" /><category term="TMC2209" /><category term="A4988" /><summary type="html"><![CDATA[Interface parallèle 16bits pour pilotage de 8 moteurs pas à pas]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://papsdroidfr.github.io//assets/images/tutos/04116bitsParallelCard/carte_300.jpg" /><media:content medium="image" url="https://papsdroidfr.github.io//assets/images/tutos/04116bitsParallelCard/carte_300.jpg" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Stepper motor</title><link href="https://papsdroidfr.github.io//dev/motor-stepper/" rel="alternate" type="text/html" title="Stepper motor" /><published>2024-08-21T00:00:00+00:00</published><updated>2024-08-21T00:00:00+00:00</updated><id>https://papsdroidfr.github.io//dev/motor-stepper</id><content type="html" xml:base="https://papsdroidfr.github.io//dev/motor-stepper/"><![CDATA[<p class="text-justify"><img src="/assets/images/tutos/040MotorStepper/motor_300.jpg" alt="Stepper" class="align-left" />
Ce <a href="https://github.com/papsdroidfr/StepperMotor">module</a> écrit en <strong>MicroPython</strong> permet de gérer un <strong>moteur pas à pas</strong> (stepper motor) avec un microcontrôleur de type Raspberry PICO, ESP32, ou SMT32. Il va permettre de définir les 4 ports GPIO qui vont commander le moteur, et de disposer de méthodes simples pour le mettre en rotation en contrôlant sa vitesse, son sens de rotation, et bien entendu de pouvoir l’arrêter sur un angle très précis, ou encore de pouvoir le mettre en veille.</p>

<h2 id="hardware">Hardware</h2>

<h3 id="matériel-nécessaire">Matériel nécessaire</h3>

<p>Il vous faut:</p>

<ul class="text-justify">
  <li>Un <strong>Raspberry PICO</strong>, ou bien un <strong>ESP32</strong> ou même un <strong>SMT32</strong> qui dispose d’au moins 4 ports GPIO</li>
</ul>
<ul class="text-justify">
  <li>Un moteur pas à pas 12v de type <strong>NEMA17</strong> (personnellement j’ai pris un modèle 17HE15-1504S)</li>
</ul>
<ul class="text-justify">
  <li>Un <strong>driver L298N</strong> qui va permettre de convertir les instructions en 3.3v envoyées par le microcontrôleur en 12v vers les bobines du moteur pas à pas.</li>
</ul>
<ul class="text-justify">
  <li>Une alimentation <strong>DC 12v ou 5v</strong>  ça fonctionne très bien en 5v: le moteur 12v aura moins de couple s’il est commandé en 5v, mais il reste parfaitement fonctionnel dans un cadre où il n’a pas beaucoup de résistance lorsqu’il doit tourner.</li>
</ul>
<ul class="text-justify">
  <li>Des petits câbles de raccord Dupont, en <strong>respectant rigoureusement le schéma ci-dessous</strong>. Si le moteur “vibre” au lieu de tourner correctement, c’est que le branchement des câbles n’est pas correct.</li>
</ul>

<figure class=" ">
  
    
      <a href="/assets/images/tutos/040MotorStepper/fritzing.png" title="Schéma du projet - Fritzing">
          <img src="/assets/images/tutos/040MotorStepper/fritzing_800.png" alt="" />
      </a>
    
  
  
    <figcaption>Cliquez pour agrandir l’image.
</figcaption>
  
</figure>

<blockquote class="text-justify">
  <p><strong>Attention</strong> une erreur très facile à faire est d’oublier de <strong>relier toutes les masses entre elles</strong>. Le fil de masse noir qui relie la masse de l’alimentation à celle du driver LN298N doit aussi être relié à la masse du microcontrôleur: c’est <strong>indispensable</strong>. (Dans mon exemple j’ai opté pour un Raspberry PICO)</p>
</blockquote>

<h3 id="fonctionnement-moteur">Fonctionnement moteur</h3>

<p class="text-justify"><img src="/assets/images/tutos/040MotorStepper/stepper_ia_300.jpg" alt="Stepper" class="align-left" />
Il faut comprendre dans les grandes lignes comment fonctionne un moteur pas à pas, pour savoir si c’est adapté à votre projet. Un tel moteur est composé de <strong>2 bobines A et B</strong>, alimentée en 12v continu (5v ça marche aussi). Dans chaque bobine, on peut injecter du 12v par ses 2 entrées. Nommons ces 4 entrées A+, A-, B+, B-.</p>
<ul class="text-justify">
  <li>C’est pour cette raison qu’il faut <strong>4 ports GPIO</strong> disponibles pour pouvoir activer l’envoi de signaux 12v sur chaque entrée.</li>
</ul>
<ul class="text-justify">
  <li>Je ne connais aucun microcontrôleur capable d’envoyer du 12v en sortie: c’est aussi pour cette raison qu’il faut un driver L298N qui va convertir les signaux (généralement en 3.3v) de sortie du microcontrôleur en tensions 12v.</li>
</ul>
<p class="text-justify">Un moteur pas à pas possède cette caractéristique de <strong>décomposer une rotation complète 360° en n “steps” égaux</strong>: on peut faire tourner le moteur d’un seul step, ce qui offre une <strong>très grande précision</strong> pour dire au moteur de tourner un angle précis, et ce <strong>sans aucun asservissement</strong> contrairement avec un moteur simple à courant continu. Les moteurs NEMA17 ont 200 steps, ce qui fait qu’on peut lui demander de tourner avec un angle multiple de 360/200 = 1.8° ! c’est très précis.</p>

<p class="text-justify">Pour que le moteur puisse tourner, il faut envoyer dans les entrées A+, A-, B+, B- un cycle précis de tensions 12v (ou 5v) et ce toutes les 5ms (ce délais d’attente est important sinon le rotor n’arrive pas à suivre le rythme). Ces tensions injectées dans les bobines ont pour conséquence de créer un champs électromagnétique qui va faire déplacer le rotor aimanté d’un “step”, et ce dans un sens comme dans l’autre selon le cycle qu’on envoie dans les bobines.</p>

<p class="text-justify"><strong>L’avantage d’un moteur pas à pas</strong> est donc de pouvoir le faire tourner dans un sens comme dans l’autre avec un angle précis sans aucun asservissement. Et bien entendu en lui disant de tourner 200 fois et de recommencer sans arrêt, il va tourner de fait en continu.</p>

<p class="text-justify">Il y a tout de même <strong>quelques inconvénients</strong> avec les moteurs pas à pas:</p>

<ul class="text-justify">
  <li><strong>Ils fonctionnent par saccades</strong> (le rotor est déplacé d’un step et attends 5ms la prochaine instruction): cela en fait des moteurs qui génèrent beaucoup de vibrations: il faut les atténuer avec du matériel qui absorbe les vibrations.</li>
</ul>

<ul class="text-justify">
  <li><strong>Ils ne sont pas rapides</strong>: on ne peut pas envisager de tourner à 10 000 tours/minute avec un moteur qui se déplace par petits steps et attend 5ms entre deux.</li>
</ul>

<ul class="text-justify">
  <li>Il faut envoyer <strong>un cycle assez casse-tête</strong> via 4 entrées de commande en 12v. Ce n’est pas aussi simple que d’activer un moteur à courant continu: une programmation informatique à l’aide d’un microcontrôleur est indispensable.</li>
</ul>

<blockquote class="text-justify">
  <p>Si vous avez besoin d’un moteur capable de tourner dans un sens comme dans l’autre, en continu ou bien avec des angles précis sans asservissement mais uniquement quelques codages informatiques, et que vous n’avez pas besoin de vitesse excessive avec les rotations: les moteurs pas à pas sont idéaux, associé avec cette bibliothèque écrite en MicroPython c’est un jeux d’enfant de l’animer sans se soucier des cycles précis à lui envoyer.</p>
</blockquote>

<h2 id="software">Software</h2>

<h3 id="installation-bibliothèque">Installation bibliothèque</h3>

<p class="text-justify">Installez bien la dernière version MicroPython sur votre microcontrôleur. Cet <a href="https://papsdroidfr.github.io/configuration/pico/">article</a> détaille comment s’y prendre avec un Raspberry PICO.</p>

<p class="text-justify">Tout le code micropython est à récupérer sur le <a href="https://github.com/papsdroidfr/StepperMotor">Github du projet</a> dans la section <strong>micropython</strong>.</p>

<p class="text-justify">Il faut ensuite importer tout le module stepper à la racine de son PICO: <strong>créer le dossier /stepper</strong> à la racine du microcontrôleur et y importer tous les programmes du module:</p>
<ul class="text-justify">
  <li><strong>__init__.py</strong>: initialisation du module</li>
</ul>
<ul class="text-justify">
  <li><strong>pibolar.py</strong>: classe de gestion du moteur</li>
</ul>
<ul class="text-justify">
  <li><strong>pinout.py</strong>: classe d’association des ports GPIO vers les entrées IN du driver LN298.</li>
</ul>

<h3 id="usage">Usage</h3>

<p class="text-justify">Ce programme montre quelques exemples de commande du moteur.</p>
<ul class="text-justify">
  <li>Une rotation complète 200 pas, à la vitesse “medium.</li>
</ul>
<ul class="text-justify">
  <li>Un demi-tour dans l’autre sens, à pleine vitesse “high”</li>
</ul>
<ul class="text-justify">
  <li>4 tours consécutifs à 90°</li>
</ul>
<ul class="text-justify">
  <li>Calcul d’un split de 200 pas en 7 tranches.</li>
</ul>

<p class="text-justify"><strong>2 directions</strong> sont à utiliser: ‘backward’(par défaut) ou ‘forward’.</p>

<p class="text-justify"><strong>4 vitesses</strong> sont proposée: speed = “high”(par défaut), “medium”, “low”, ou “test”. La vitesse speed=’test’ permet de voir le moteur tourner step par step à très basse vitesse (1/2 secondes entre chaque): vous pouvez ainsi constater sur une dizaine de steps qu’il tourne bien toujours dans le même sens. Si ce n’est pas le cas, c’est que les branchements sont à revoir (et du coup il vibre au lieu de tourner à grande vitesse).</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">import</span> <span class="nn">utime</span>
<span class="kn">from</span> <span class="nn">stepper.bipolar</span> <span class="kn">import</span> <span class="n">BipolarStepper</span>

<span class="k">print</span><span class="p">(</span><span class="s">'test module stepper'</span><span class="p">)</span>
<span class="n">bp</span> <span class="o">=</span> <span class="n">BipolarStepper</span><span class="p">(</span><span class="n">speed</span><span class="o">=</span><span class="s">'medium'</span><span class="p">)</span>   

<span class="k">print</span><span class="p">(</span><span class="s">'move 200 steps forward, speed medium'</span><span class="p">)</span> 
<span class="n">bp</span><span class="p">.</span><span class="n">next_steps</span><span class="p">(</span><span class="mi">200</span><span class="p">)</span>
<span class="n">bp</span><span class="p">.</span><span class="n">sleep</span><span class="p">()</span>
<span class="n">utime</span><span class="p">.</span><span class="n">sleep</span><span class="p">(</span><span class="mf">0.5</span><span class="p">)</span>

<span class="k">print</span><span class="p">(</span><span class="s">'move 100 steps backward highest speed'</span><span class="p">)</span>
<span class="n">bp</span><span class="p">.</span><span class="n">set_direction</span><span class="p">(</span><span class="s">'backward'</span><span class="p">)</span>            
<span class="n">bp</span><span class="p">.</span><span class="n">set_speed</span><span class="p">(</span><span class="s">'high'</span><span class="p">)</span>            
<span class="n">bp</span><span class="p">.</span><span class="n">next_steps</span><span class="p">(</span><span class="mi">100</span><span class="p">)</span>
<span class="n">bp</span><span class="p">.</span><span class="n">sleep</span><span class="p">()</span>
<span class="n">utime</span><span class="p">.</span><span class="n">sleep</span><span class="p">(</span><span class="mf">0.5</span><span class="p">)</span>
    
<span class="k">print</span><span class="p">(</span><span class="s">'move 4 times to 90°'</span><span class="p">)</span>
<span class="k">for</span> <span class="n">_</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">4</span><span class="p">):</span>
    <span class="n">bp</span><span class="p">.</span><span class="n">next_angle</span><span class="p">(</span><span class="mi">90</span><span class="p">)</span>
    <span class="n">bp</span><span class="p">.</span><span class="n">sleep</span><span class="p">()</span>
    <span class="n">utime</span><span class="p">.</span><span class="n">sleep</span><span class="p">(</span><span class="mf">0.5</span><span class="p">)</span>

<span class="k">print</span><span class="p">(</span><span class="sa">f</span><span class="s">"split </span><span class="si">{</span><span class="n">bp</span><span class="p">.</span><span class="n">steps360</span><span class="si">}</span><span class="s"> steps in 7: </span><span class="si">{</span><span class="n">bp</span><span class="p">.</span><span class="n">split_steps</span><span class="p">(</span><span class="mi">7</span><span class="p">)</span><span class="si">}</span><span class="s">"</span><span class="p">)</span>

<span class="n">bp</span><span class="p">.</span><span class="n">sleep</span><span class="p">()</span>
<span class="k">print</span><span class="p">(</span><span class="s">'bye'</span><span class="p">)</span>
</code></pre></div></div>

<blockquote class="text-justify">
  <p>Si le moteur vibre au lieu de tourner correctement avec ce programme test, c’est que vos branchements sont à revoir.</p>
</blockquote>

<p class="text-justify">Si vous voulez utiliser <strong>d’autres GPIO</strong> que ceux utilisés par défaut (GPIO_17:in1, GPIO_16:in2, GPIO_15:in3, GPIO_14:in4), il suffit de passer les paramètres pin1=mon_gpio1, pin2=mon_gpio2, pin3=mon_gpio3 et pin4=mon_gpio4 lors de l’instanciation d’un objet bp=BipolarStepper(), exemple ci-dessous avec les GPIO 10 à 13:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">bp</span> <span class="o">=</span> <span class="n">BipolarStepper</span><span class="p">(</span><span class="n">speed</span><span class="o">=</span><span class="s">'medium'</span><span class="p">,</span> <span class="n">in1</span><span class="o">=</span><span class="mi">10</span><span class="p">,</span> <span class="n">in2</span><span class="o">=</span><span class="mi">11</span><span class="p">,</span> <span class="n">in3</span><span class="o">=</span><span class="mi">12</span><span class="p">,</span> <span class="n">in4</span><span class="o">=</span><span class="mi">13</span><span class="p">)</span> 
</code></pre></div></div>

<p>Enfin si votre moteur pas à pas ne fait pas 200 steps, utilisez la variable <strong>steps360</strong> (par défaut initialisée à 200) pour le préciser.</p>

<p class="text-justify">Notez bien que la <strong>méthode sleep()</strong> est très importante pour <strong>mettre le moteur en veille</strong> et ne plus envoyer de tension dans les 4 fils de commande. Dans ce cas, le moteur est relâché et ne consomme plus aucun courant. On peut le faire tourner à la main puisque le rotor n’est plus maintenu en place par un champs électromagnétique. Attention s’il subi un couple de contrainte trop importante il va se mettre à tourner tout seul pour retrouver son équilibre sans contrainte …</p>

<p class="text-justify">A l’inverse si vous ne mettez pas le moteur en veille avec cette méthode .sleep(), 2 des 4 fils restent sous tension et vont maintenir avec force le rotor en place: c’est quasiment impossible de le faire bouger à la main. Mais du 12v est envoyé en continu dans les bobines: <strong>le radiateur du LN298 va se mettre à pas mal chauffer</strong> !</p>

<h3 id="pour-aller-plus-loin">Pour aller plus loin</h3>

<ul class="text-justify">
  <li>Vous pouvez vous amuser à brancher 4 leds (avec leur résistance) en // des 4 sortie GPIO et utiliser la vitesse ‘test’ pour les voir s’allumer selon le cycle de séquence programmé. Les autres vitesses vont trop vite pour nos yeux: vous aurez l’impression que les 4 leds sont tout le temps allumées.</li>
</ul>

<ul class="text-justify">
  <li>Si vous voulez commander <strong>plusieurs moteurs</strong> avec le même microcontrôleur il suffit d’instancier plusieurs objets BipolarStepper() mais avec des GPIO différents pour chaque moteur. Il faut 4 GPIO de libre par moteur.</li>
</ul>]]></content><author><name>PapsDroid</name><email>papsdroid.fr@gmail.com</email></author><category term="DEV" /><category term="micro-python" /><category term="raspberry pico" /><category term="ESP32" /><category term="stepper-motor" /><category term="L298N" /><summary type="html"><![CDATA[Une bibliothèque MicroPython pour contrôler un moteur pas à pas - Stepper Motor]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://papsdroidfr.github.io//assets/images/tutos/040MotorStepper/motor_300.jpg" /><media:content medium="image" url="https://papsdroidfr.github.io//assets/images/tutos/040MotorStepper/motor_300.jpg" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">PICO Web Server</title><link href="https://papsdroidfr.github.io//dev/PICO-Web-Server/" rel="alternate" type="text/html" title="PICO Web Server" /><published>2024-08-18T00:00:00+00:00</published><updated>2024-08-18T00:00:00+00:00</updated><id>https://papsdroidfr.github.io//dev/PICO-Web-Server</id><content type="html" xml:base="https://papsdroidfr.github.io//dev/PICO-Web-Server/"><![CDATA[<p class="text-justify"><img src="/assets/images/tutos/039PicoWeb/screenshot1_300.png" alt="PICOWeb" class="align-left" />
Ce module écrit en <strong>MicroPython</strong> permet de gérer un <strong>serveur WEB</strong> sur un <strong>Raspberry PICO</strong> afin de prendre le contrôle des commandes depuis son smartphone, par exemple pour commander un moteur. Ce serveur va écouter sur le thread principal les requêtes reçues d’une connexion externe http et générer de manière dynamique une page HTML et un évènement en réponse à la requête http reçue. Les événements générés par le serveur WEB sont lus en boucle dans un second thread (<strong>multithread</strong>) qui va agir en fonction de l’événement lu: comme par exemple démarrer un moteur, ou l’arrêter etc…</p>

<h2 id="hardware">Hardware</h2>

<p class="text-justify">Un <strong>Raspberry PICO</strong> version 1 W(H) ou encore version 2, ainsi qu’une connexion WIFI. L’avantage d’utiliser un Raspberry PICO est qu’il dispose d’un <strong>double cœur</strong>: le multithread y est particulièrement efficace. Si vous utilisez un ESP32-S3 (aussi double cœur), il faut juste adapter le code de la led.py qui est spécifique à la led du PICO. Si vous utilisez un ESP32-C3 mono-cœur: les threads vont se marcher sur les pieds et rendre l’expérience assez désastreuse (serveur WEB qui ne répond pas tout de suite, ou événement traité par saccades et ralentissements)</p>

<blockquote class="text-justify">
  <p>A l’heure où j’écris cet article je n’ai pas encore reçu de <strong>PICO version 2</strong> (pré-commandes fin août 2024). Une version PICO 2 est vivement conseillée car il dispose d’une <strong>architecture de sécurité</strong> basée sur Arm TrustZOne qui permet d’isoler et sécuriser tout le code micropython, et surtout le mot de passe de connexion wifi, ce que ne propose ni la version 1 du PICO, ni les ESP32-S3 où les password wifi circulent soient en clair dans les fichiers de configuration, ou alors cryptés mais avec le code python de décryptage ainsi que les clés à disposition: moi ça me prendrait 5 secondes à craquer un tel password crypté de cette façon.</p>
</blockquote>

<h2 id="software">Software</h2>

<p class="text-justify">Installez bien la dernière version MicroPython sur votre Raspberry PICO. Cet <a href="https://papsdroidfr.github.io/configuration/pico/">article</a> détaille comment s’y prendre.</p>

<p class="text-justify">Tout le code micropython est à récupérer sur le <a href="https://github.com/papsdroidfr/PICO-Webserver">Github du projet</a>.</p>

<p class="text-justify">Il faut ensuite importer tout le module web à la racine de son PICO: créer le dossier /web et y importer tous les programmes du module.</p>

<ul class="text-justify">
  <li><strong>__init__.py</strong>: initialisation du module</li>
  <li><strong>config.py</strong>: variables globales utilisées par le module, on y retrouve le SSID et le PASSWORD wifi à utiliser, et qui serait en bien meilleure sécurité sur un Raspberry PICO 2.</li>
  <li><strong>log.py</strong>: gestion interne des messages.</li>
</ul>
<ul class="text-justify">
  <li><strong>led.py</strong>: gestion de la led du PICO (à adapter si vous n’utilisez pas un PICO)</li>
</ul>
<ul class="text-justify">
  <li><strong>server.py</strong>: gestion du serveur web avec une page HTML par défaut “hello PICO WWWorld!”</li>
</ul>
<ul>
  <li><strong>wifi.py</strong>: gestion du WIFI.</li>
</ul>

<h3 id="usage">Usage</h3>

<p class="text-justify">Le principe du serveur et géré dans le programme <strong>server.py</strong> où deux classes principales sont définies:</p>

<ul class="text-justify">
  <li><strong>classe Event()</strong>: Gère la création des évènements par le serveur. Cette classe défini le dictionnaire des actions à exécuter pour chaque évènement.</li>
</ul>
<ul class="text-justify">
  <li><strong>classe Server()</strong>: Gère tout le serveur Web en commençant par se connecter au WIFI, puis démarre dans un thread dédié la lecture en boucle des événements pour agir en conséquence, et démarre ensuite le serveur WEB qui écoute les requêtes reçues dans le thread principal, pour générer un code HTML dynamique ainsi qu’un événement adéquat.</li>
</ul>

<blockquote class="text-justify">
  <p>Ces 3 lignes de code vous permettent de démarrer un serveur WEB par défaut:</p>
</blockquote>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">from</span> <span class="nn">web.wifi</span> <span class="kn">import</span> <span class="n">Wifi</span>
<span class="kn">from</span> <span class="nn">web.server</span> <span class="kn">import</span> <span class="n">Server</span>

<span class="n">my_server</span> <span class="o">=</span> <span class="n">Server</span><span class="p">(</span><span class="n">wifi</span><span class="o">=</span><span class="n">Wifi</span><span class="p">(),</span> <span class="n">debug</span><span class="o">=</span><span class="bp">True</span><span class="p">)</span>
</code></pre></div></div>
<p><img src="/assets/images/tutos/039PicoWeb/screenshot1_640.png" alt="PICOWeb" class="align-center" />
<img src="/assets/images/tutos/039PicoWeb/log1.png" alt="PICOWeb" class="align-center" /></p>

<blockquote class="text-justify">
  <p>On ne retrouve pas toutes les fonctionnalités de Python dans MicroPython, il n’y a pas de notion de <strong>classes abstraites</strong> qui eut été bien utile dans mon cas pour définir les classes génériques qui gèrent le serveur WEB et les évènements. Pour contourner cette limitation il suffit de recréer vos propres classes  qui héritent chacune des classes Server() et Event() et de surcharger les fonctions principales, notamment le <strong>dictionnaire des évènements</strong> de la classe Event() et les méthodes <strong>Server._thread_loop_event(self)</strong> (réaction aux événements) ainsi que <strong>Server._gen_html()</strong> (le générateur dynamique de code HTML)</p>
</blockquote>

<h3 id="exemple-de-code">Exemple de code</h3>

<p class="text-justify">Dans l’exemple de code ci-dessous, je souhaite créer un serveur WEB avec <strong>5 événements</strong> pour contrôler le moteur de mon <a href="https://papsdroidfr.github.io/tutoriels/soleil-terre-lune/">planétaire mécanique Soleil-Terre-Lune</a> afin de simuler une journée, une semaine, un mois, ou bien de mettre en marche le moteur et bien entendu de pouvoir l’arrêter à tout moment.</p>

<p><img src="/assets/images/tutos/039PicoWeb/screenshot2.png" alt="PICOWeb" class="align-center" /></p>

<p class="text-justify">On commence par les imports nécessaires.</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">import</span> <span class="nn">time</span>
<span class="kn">from</span> <span class="nn">web.wifi</span> <span class="kn">import</span> <span class="n">Wifi</span>
<span class="kn">from</span> <span class="nn">web.server</span> <span class="kn">import</span> <span class="n">Event</span><span class="p">,</span> <span class="n">Server</span>
</code></pre></div></div>

<p class="text-justify">Ensuite nous créons notre classe de <strong>gestion des évènements</strong> qui va hériter de la classe Event(), afin de sur-définir le dictionnaire des actions pour chaque évènement. Attention ne pas oublier d’appeler le constructeur de la classe mère super().__init__(). Pour l’exemple les actions ne sont que des prints sur la console, mais on peut imaginer commander un moteur, interagir avec des leds etc …</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">class</span> <span class="nc">EventPlanetarium</span><span class="p">(</span><span class="n">Event</span><span class="p">):</span>
    <span class="s">""" This class manages event raised by the webserver to run planetarium"""</span>
    <span class="k">def</span> <span class="nf">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span><span class="o">-&gt;</span> <span class="bp">None</span><span class="p">:</span>
        <span class="c1">#Events managed by the web server
</span>        <span class="nb">super</span><span class="p">().</span><span class="n">__init__</span><span class="p">()</span>
        
        <span class="c1">#my own events
</span>        <span class="bp">self</span><span class="p">.</span><span class="n">EVENT_RUN1D</span><span class="p">:</span> <span class="nb">str</span> <span class="o">=</span> <span class="s">'Tourne 1 jour'</span>    <span class="c1">#run planetarium for 1 day
</span>        <span class="bp">self</span><span class="p">.</span><span class="n">EVENT_RUN1W</span><span class="p">:</span> <span class="nb">str</span> <span class="o">=</span> <span class="s">'Tourne 1 semaine'</span> <span class="c1">#run planetarium for 1 week
</span>        <span class="bp">self</span><span class="p">.</span><span class="n">EVENT_RUN1M</span><span class="p">:</span> <span class="nb">str</span> <span class="o">=</span> <span class="s">'Tourne 1 mois'</span>    <span class="c1">#run planetarium for 1 month
</span>        <span class="bp">self</span><span class="p">.</span><span class="n">EVENT_RUN</span><span class="p">:</span>   <span class="nb">str</span> <span class="o">=</span> <span class="s">'En marche'</span>        <span class="c1">#run planetarium
</span>        <span class="bp">self</span><span class="p">.</span><span class="n">EVENT_STOP</span><span class="p">:</span>  <span class="nb">str</span> <span class="o">=</span> <span class="s">'STOP'</span>             <span class="c1">#stop planetarium
</span>        
        <span class="c1">#dictionnary of actions for each event name
</span>        <span class="bp">self</span><span class="p">.</span><span class="n">actions</span><span class="o">=</span><span class="p">{</span>
            <span class="bp">self</span><span class="p">.</span><span class="n">EVENT_NONE</span><span class="p">:</span> <span class="bp">self</span><span class="p">.</span><span class="n">action_none</span><span class="p">,</span>
            <span class="bp">self</span><span class="p">.</span><span class="n">EVENT_RUN1D</span><span class="p">:</span> <span class="bp">self</span><span class="p">.</span><span class="n">action_run_1d</span><span class="p">,</span>
            <span class="bp">self</span><span class="p">.</span><span class="n">EVENT_RUN1W</span><span class="p">:</span> <span class="bp">self</span><span class="p">.</span><span class="n">action_run_1w</span><span class="p">,</span>
            <span class="bp">self</span><span class="p">.</span><span class="n">EVENT_RUN1M</span><span class="p">:</span> <span class="bp">self</span><span class="p">.</span><span class="n">action_run_1m</span><span class="p">,</span>
            <span class="bp">self</span><span class="p">.</span><span class="n">EVENT_RUN</span><span class="p">:</span> <span class="bp">self</span><span class="p">.</span><span class="n">action_run</span><span class="p">,</span>
            <span class="bp">self</span><span class="p">.</span><span class="n">EVENT_STOP</span><span class="p">:</span> <span class="bp">self</span><span class="p">.</span><span class="n">action_stop</span><span class="p">,</span>
        <span class="p">}</span>

    <span class="k">def</span> <span class="nf">action_run_1d</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
        <span class="k">print</span><span class="p">(</span><span class="s">'Start run 1D'</span><span class="p">)</span>
        <span class="n">time</span><span class="p">.</span><span class="n">sleep</span><span class="p">(</span><span class="mf">0.5</span><span class="p">)</span>
        <span class="k">print</span><span class="p">(</span><span class="s">'End run 1D'</span><span class="p">)</span>
    
    <span class="k">def</span> <span class="nf">action_run_1w</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
        <span class="k">print</span><span class="p">(</span><span class="s">'Start run 1W'</span><span class="p">)</span>
        <span class="n">time</span><span class="p">.</span><span class="n">sleep</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>
        <span class="k">print</span><span class="p">(</span><span class="s">'End run 1W'</span><span class="p">)</span>

    <span class="k">def</span> <span class="nf">action_run_1m</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
        <span class="k">print</span><span class="p">(</span><span class="s">'Start run 1M'</span><span class="p">)</span>
        <span class="n">time</span><span class="p">.</span><span class="n">sleep</span><span class="p">(</span><span class="mi">4</span><span class="p">)</span>
        <span class="k">print</span><span class="p">(</span><span class="s">'End run 1M'</span><span class="p">)</span>

    <span class="k">def</span> <span class="nf">action_run</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
        <span class="k">print</span><span class="p">(</span><span class="s">'Start run'</span><span class="p">)</span>
        <span class="k">while</span> <span class="bp">self</span><span class="p">.</span><span class="n">event_raised</span> <span class="o">==</span> <span class="bp">self</span><span class="p">.</span><span class="n">EVENT_RUN</span><span class="p">:</span>
            <span class="k">print</span><span class="p">(</span><span class="s">'...press STOP...'</span><span class="p">)</span>
            <span class="n">time</span><span class="p">.</span><span class="n">sleep</span><span class="p">(</span><span class="mf">0.5</span><span class="p">)</span>

    <span class="k">def</span> <span class="nf">action_stop</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
        <span class="k">print</span><span class="p">(</span><span class="s">'Action STOP'</span><span class="p">)</span>
</code></pre></div></div>

<p class="text-justify">Enfin nous créons notre propre classe de <strong>serveur web</strong> qui va hériter de la classe Server() afin de sur-définir notre propre <strong>générateur de code HTML</strong> _gen_html() et notre propre <strong>générateur d’évènements</strong> _raise_event().</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">class</span> <span class="nc">ServerWeb</span><span class="p">(</span><span class="n">Server</span><span class="p">):</span>
    
    <span class="k">def</span> <span class="nf">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">debug</span><span class="p">:</span><span class="nb">bool</span> <span class="o">=</span> <span class="bp">False</span><span class="p">)</span><span class="o">-&gt;</span> <span class="bp">None</span><span class="p">:</span>
        <span class="nb">super</span><span class="p">().</span><span class="n">__init__</span><span class="p">(</span><span class="n">wifi</span><span class="o">=</span><span class="n">Wifi</span><span class="p">(),</span> <span class="n">event</span> <span class="o">=</span> <span class="n">EventPlanetarium</span><span class="p">(),</span> <span class="n">debug</span><span class="o">=</span><span class="n">debug</span><span class="p">)</span>
     
    <span class="k">def</span> <span class="nf">_gen_html</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span><span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
 
        <span class="n">html</span> <span class="o">=</span> <span class="sa">f</span><span class="s">"""&lt;html&gt;
            </span><span class="si">{</span><span class="bp">self</span><span class="p">.</span><span class="n">HEAD_HTML</span><span class="si">}</span><span class="s">
            &lt;body&gt;
                &lt;h1&gt;Soleil-Terre-Lune&lt;/h1&gt;
                &lt;p&gt;&lt;a href=https://papsdroidfr.github.io/tutoriels/soleil-terre-lune/&gt; &lt;Construire la maquette&gt; &lt;/a&gt;&lt;/p&gt;
                &lt;p&gt;Action en cours: &lt;strong&gt; </span><span class="si">{</span><span class="bp">self</span><span class="p">.</span><span class="n">event_raised</span><span class="si">}</span><span class="s"> &lt;/strong&gt;&lt;/p&gt;
                &lt;p&gt;&lt;a href="/?event=runFull"&gt;&lt;button class="button"&gt;Marche&lt;/button&gt;&lt;/a&gt;&lt;/p&gt;
                &lt;p&gt;&lt;a href="/?event=run1D"&gt;&lt;button class="button"&gt;1 jour&lt;/button&gt;&lt;/a&gt;&lt;/p&gt;
                &lt;p&gt;&lt;a href="/?event=run1W"&gt;&lt;button class="button"&gt;1 semaine&lt;/button&gt;&lt;/a&gt;&lt;/p&gt;
                &lt;p&gt;&lt;a href="/?event=run1M"&gt;&lt;button class="button"&gt;1 mois&lt;/button&gt;&lt;/a&gt;&lt;/p&gt;
                &lt;p&gt;&lt;a href="/?event=stop"&gt;&lt;button class="button button_red"&gt;STOP&lt;/button&gt;&lt;/a&gt;&lt;/p&gt;
            &lt;/body&gt;
        &lt;/html&gt;"""</span>
        
        <span class="k">return</span> <span class="nb">str</span><span class="p">(</span><span class="n">html</span><span class="p">)</span>

    <span class="k">def</span> <span class="nf">_raise_event</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">request</span><span class="p">:</span><span class="nb">str</span><span class="p">)</span><span class="o">-&gt;</span> <span class="bp">None</span><span class="p">:</span>
        <span class="s">""" Set event raised, depends on request"""</span>
        <span class="k">if</span> <span class="n">request</span><span class="p">.</span><span class="n">find</span><span class="p">(</span><span class="s">'GET /?event=runFull'</span><span class="p">)</span> <span class="o">&gt;</span> <span class="o">-</span><span class="mi">1</span><span class="p">:</span>
            <span class="bp">self</span><span class="p">.</span><span class="n">event</span><span class="p">.</span><span class="n">set_event</span><span class="p">(</span><span class="bp">self</span><span class="p">.</span><span class="n">event</span><span class="p">.</span><span class="n">EVENT_RUN</span><span class="p">)</span>
        <span class="k">elif</span> <span class="n">request</span><span class="p">.</span><span class="n">find</span><span class="p">(</span><span class="s">'GET /?event=stop'</span><span class="p">)</span> <span class="o">&gt;</span> <span class="o">-</span><span class="mi">1</span><span class="p">:</span>
            <span class="bp">self</span><span class="p">.</span><span class="n">event</span><span class="p">.</span><span class="n">set_event</span><span class="p">(</span><span class="bp">self</span><span class="p">.</span><span class="n">event</span><span class="p">.</span><span class="n">EVENT_STOP</span><span class="p">)</span>
        
        <span class="k">elif</span> <span class="bp">self</span><span class="p">.</span><span class="n">event_raised</span> <span class="o">!=</span> <span class="bp">self</span><span class="p">.</span><span class="n">event</span><span class="p">.</span><span class="n">EVENT_RUN</span><span class="p">:</span>
            <span class="k">if</span> <span class="n">request</span><span class="p">.</span><span class="n">find</span><span class="p">(</span><span class="s">'GET /?event=run1D'</span><span class="p">)</span> <span class="o">&gt;</span> <span class="o">-</span><span class="mi">1</span><span class="p">:</span>
                <span class="bp">self</span><span class="p">.</span><span class="n">event</span><span class="p">.</span><span class="n">set_event</span><span class="p">(</span><span class="bp">self</span><span class="p">.</span><span class="n">event</span><span class="p">.</span><span class="n">EVENT_RUN1D</span><span class="p">)</span>
            <span class="k">elif</span> <span class="n">request</span><span class="p">.</span><span class="n">find</span><span class="p">(</span><span class="s">'GET /?event=run1W'</span><span class="p">)</span> <span class="o">&gt;</span> <span class="o">-</span><span class="mi">1</span><span class="p">:</span>
                <span class="bp">self</span><span class="p">.</span><span class="n">event</span><span class="p">.</span><span class="n">set_event</span><span class="p">(</span><span class="bp">self</span><span class="p">.</span><span class="n">event</span><span class="p">.</span><span class="n">EVENT_RUN1W</span><span class="p">)</span>
            <span class="k">elif</span> <span class="n">request</span><span class="p">.</span><span class="n">find</span><span class="p">(</span><span class="s">'GET /?event=run1M'</span><span class="p">)</span> <span class="o">&gt;</span> <span class="o">-</span><span class="mi">1</span><span class="p">:</span>
                <span class="bp">self</span><span class="p">.</span><span class="n">event</span><span class="p">.</span><span class="n">set_event</span><span class="p">(</span><span class="bp">self</span><span class="p">.</span><span class="n">event</span><span class="p">.</span><span class="n">EVENT_RUN1M</span><span class="p">)</span>
            <span class="k">else</span><span class="p">:</span>
                <span class="bp">self</span><span class="p">.</span><span class="n">event</span><span class="p">.</span><span class="n">set_event</span><span class="p">(</span><span class="bp">self</span><span class="p">.</span><span class="n">event</span><span class="p">.</span><span class="n">EVENT_NONE</span><span class="p">)</span>
        
        <span class="n">time</span><span class="p">.</span><span class="n">sleep</span><span class="p">(</span><span class="mf">0.2</span><span class="p">)</span>
</code></pre></div></div>

<p class="text-justify">Il reste à démarrer ce web serveur</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">#start web serveur
</span><span class="n">my_server</span> <span class="o">=</span> <span class="n">ServerWeb</span><span class="p">(</span><span class="n">debug</span><span class="o">=</span><span class="bp">True</span><span class="p">)</span>
</code></pre></div></div>

<blockquote class="text-justify">
  <p>Dans cet exemple, les actions ne sont matérialisées que par des “print” dans la console et un temps d’attente. Pour ce qui est de la réaction aux évènements, je met la priorité sur les événements STOP et MARCHE. Tous les autres évènements sont ignorés dès que l’utilisateur à cliqué sur le bouton “MARCHE”: il faudra d’abord appuyer sur STOP.</p>
</blockquote>

<h3 id="pour-aller-plus-loin">Pour aller plus loin</h3>

<p class="text-justify">Dans un projet finalisé, il n’y aura pas besoin de faire tous ces print dans la log: il faudra instancier le ServerWeb avec l’option <strong>debug=False</strong>. Pour récupérer l’adresse du serveur WEB généré par le PICO il y a deux façons de faire:</p>

<ul class="text-justify">
  <li>Utiliser un petit écran OLED ou LCD pour y afficher l’adresse du serveur WEB.</li>
</ul>
<ul class="text-justify">
  <li>Si vous utilisez un smartphone Android, l’application “<strong>Net Analyser</strong>” analyse et scanne tous les serveurs LAN actifs sur le réseau WIFI: on détecte ainsi facilement l’adresse du serveur WEB géré par le PICO.</li>
</ul>]]></content><author><name>PapsDroid</name><email>papsdroid.fr@gmail.com</email></author><category term="DEV" /><category term="micro-python" /><category term="raspberry pico" /><category term="multi-thread" /><summary type="html"><![CDATA[Un serveur WEB en MicroPython pour Raspberry PICO]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://papsdroidfr.github.io//assets/images/tutos/039PicoWeb/screenshot1_300.png" /><media:content medium="image" url="https://papsdroidfr.github.io//assets/images/tutos/039PicoWeb/screenshot1_300.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Planétaire: Soleil Terre Lune</title><link href="https://papsdroidfr.github.io//tutoriels/soleil-terre-lune/" rel="alternate" type="text/html" title="Planétaire: Soleil Terre Lune" /><published>2024-05-30T00:00:00+00:00</published><updated>2024-05-30T00:00:00+00:00</updated><id>https://papsdroidfr.github.io//tutoriels/soleil-terre-lune</id><content type="html" xml:base="https://papsdroidfr.github.io//tutoriels/soleil-terre-lune/"><![CDATA[<p class="text-justify"><img src="/assets/images/tutos/038SoleilTerreLune/header.jpeg" alt="Planétaire" class="align-left" />
Cet article détaille l’assemblage de la maquette d’un nouveau <a href="https://papsdroidfr.github.io/tags/#planétaire">#planétaire</a> mécanique entièrement imprimé 3D. Il est composé du système <strong>(Soleil, Terre, Lune)</strong> animé, avec en option une motorisation électronique. Les périodes de révolution et de rotation sont respectées, ainsi que l’axe d’inclinaison de la Terre, ce qui permet d’expliquer visuellement les saisons. La maquette est parfaitement fonctionnelle sans le moteur grâce à un volant.</p>

<h2 id="matériel-nécessaire">Matériel nécessaire</h2>

<p class="text-justify">Une imprimante 3D avec un plateau de dimension minimum <strong>30cmx30cm</strong> minimum.</p>
<p class="text-justify">Quelques bobines de PLA (la maquette pèse 1,2 kg en tout), j’ai utilisé comme couleurs:</p>
<ul>
  <li>Orange pour les pieds.</li>
  <li>Rouge pour tous les axes et roues dentées qui vont faire un tour complet pour 1 jour.</li>
  <li>Gris foncé pour les plateaux.</li>
  <li>Blanc pour les roues dentées.</li>
  <li>Noir pour les axes.</li>
  <li>Gris clair pour la Lune.</li>
  <li>Bleu pour la Terre.</li>
  <li>Jaune pour le Soleil.</li>
</ul>

<p class="text-justify">De la colle pour assembler quelques pièces (le Soleil, la Terre et les pieds notamment).</p>
<p class="text-justify">Optionnel: des petits patins de protection (comme ceux que l’on met sous les pieds de chaise) pour limiter les vibrations des pieds lorsqu’on utilise un moteur.</p>

<h2 id="consignes">Consignes</h2>

<blockquote class="text-justify">
  <p>Tous les fichiers STL sont à disposition sur mon profil <a href="https://cults3d.com/fr/mod%C3%A8le-3d/art/planetaire-soleil-terre-lune">cults3D</a></p>
</blockquote>

<p class="text-justify">J’encourage à imprimer les éléments d’une seule étape et de les assembler avant de passer à l’étape suivante. Si vous imprimez tout d’un coup, vous allez galérer à retrouver les bonnes roues dentées ou les bons axes de chaque étape. Si vous orientez correctement les pièces lors de l’impression (surface plate au sol) vous n’aurez <strong>pas besoin de support</strong>. Vous pouvez imprimer en <strong>définition 0.3mm</strong> pour gagner du temps, c’est largement suffisant car il n’y a pas de détail fin vertical (comme sur une figurine) qui nécessite d’imprimer en plus petites couches.</p>
<p class="text-justify">Attention certaines pièces font plus que 25cm de long (notamment les supports): cette maquette nécessite une surface d’impression d’au <strong>minimum 30cm x 30cm</strong>.</p>
<p class="text-justify">Chaque fichier STL commence par le numéro de l’étape afin de vous orienter dans le bon ordre d’impression. Les couleurs sont suggérées dans chaque image: pieds en orange, manivelle et tous les axes et roues qui tournent à la vitesse de 1 jour par tour en rouge, autres roues en blanc, axes en noir, supports en gris foncé. Soleil et son axe en jaune, Terre en bleu, Lune en gris clair. Une petite astuce concernant le plateau circulaire pour imprimer les lettrages en blanc sur fond gris foncé sera expliquée lors de cette étape.</p>

<h2 id="étapes">Étapes</h2>

<h3 id="01-pieds">01: Pieds</h3>

<p class="text-justify"><img src="/assets/images/tutos/038SoleilTerreLune/01_pieds.png" alt="Planétaire" class="align-center" />
Commencez par imprimer (couleur suggérée: orange) tous les pieds de l’étape 01. le pied_extérieur(x4) est à imprimer 4 fois. Le pied_intérieur(x3) est à imprimer 3 fois … vous aurez compris le principe pour la suite: j’indique à chaque fois s’il faut imprimer la même pièce plusieurs fois. Disposez ensuite les pieds à peu près comme sur la photo.</p>

<h3 id="02-plateau-circulaire">02: Plateau circulaire</h3>

<p class="text-justify"><img src="/assets/images/tutos/038SoleilTerreLune/02_plateau_circulaire.png" alt="Planétaire" class="align-center" />
Pour imprimer les 4 éléments circulaires de la base, j’ai utilisé 2 couleurs en commençant par du blanc sur les couches inférieures, puis du gris foncés sur les couches supérieures de manières à ce que les lettrages apparaissent en blanc sur fond gris foncé. Si vous optez en une définition de <strong>couche de 0.3mm</strong>, il faut changer de bobine au début de la <strong>8ème couche</strong> pour obtenir cet effet. le socle_base quand à lui s’imprime en une seule couleur (gris foncé).</p>

<p class="text-justify">Assemblez les éléments comme sur la photo. N’hésitez pas à <strong>ébarber avec un cuter les surplus de matière</strong> qui empêcheraient d’assembler les 1/4 de cercle entre eux ainsi qu’au socle_base: c’est fait pour être serré, calculé au 1/10ème de mm près. Pour assembler le pied qui va maintenir le moteur et la manivelle, ne pas hésiter à <strong>tapper avec un petit marteau</strong>: ça rentre de justesse, c’est fait exprès. Pour les autres pieds vous pouvez <strong>utiliser de la colle</strong> pour les fixer sur le socle circulaire.</p>

<p class="text-justify"><strong>Optionnel</strong>: pour améliorer l’accroche de la maquette au sol, j’ai rajouté sous chaque pied des petits patins que l’on met habituellement sous les pieds de chaises pour éviter de cogner les parquets. Si vous utilisez un moteur: ça limitera les vibrations.</p>

<h3 id="03-manivelle">03: Manivelle</h3>

<figure class=""><img src="/assets/images/tutos/038SoleilTerreLune/03_manivelle_assemblage.png" alt="" /><figcaption>
      Assemblage de la manivelle sur les pieds du socle.

    </figcaption></figure>

<p class="text-justify"><img src="/assets/images/tutos/038SoleilTerreLune/03_manivelle_300.png" alt="Planétaire" class="align-left" />
Les éléments de la manivelle sont imprimés en rouge. Pensez à bien <strong>orienter surface plate au sol</strong> la roue dentée et le volant (attention ils ont tous les deux une collerettes sur une face). Je conseille d’imprimer tous <strong>les axes à la verticale</strong> (pas besoin d’utiliser de bordure ni de radeau pour augmenter la surface d’accroche). Si vous les imprimez à l’horizontale, vous allez subir une petite déformation de la base au sol, et l’axe ne va pas bien tourner dans son logement après.</p>

<blockquote class="text-justify">
  <p>Mettez de côté tout cet ensemble pieds, plateau circulaire et manivelle. Vous aller dans les sections suivantes assembler tout le mécanisme du planétaire à part, et le poser sur le plateau circulaire en toute dernière étape.</p>
</blockquote>

<h3 id="04-base">04: Base</h3>

<figure class="half ">
  
    
      <a href="/assets/images/tutos/038SoleilTerreLune/04_base_640_1.png" title="Assemblage de la base">
          <img src="/assets/images/tutos/038SoleilTerreLune/04_base_300_1.png" alt="" />
      </a>
    
  
    
      <a href="/assets/images/tutos/038SoleilTerreLune/04_base_640_2.png" title="Montage final">
          <img src="/assets/images/tutos/038SoleilTerreLune/04_base_300_2.png" alt="" />
      </a>
    
  
  
    <figcaption>Cliquez pour agrandir les images
</figcaption>
  
</figure>

<p class="text-justify">Les axes, roues dentées et collerettes sont à imprimer en rouge (toujours surface plate au sol, axe et collerettes à la verticale). J’ai imprimé les base_support_bas et haut en gris foncé. Pensez à bien réorienter la pièce base_support_haut dans l’autre sens: surface plate au sol et pas besoin de support dans cette configuration. Suivez la photo de gauche (cliquez dessous pour agrandir) pour voir comment assembler les pièces. Ne vous trompez pas entre les deux roues de 28 dents l’une est à disposer sur l’axe horizontal, l’autre sur l’axe vertical (elles sont différentes). N’oubliez pas les collerettes. Le mécanisme doit être fluide une fois que tout est assemblé.</p>

<p class="text-justify">La petite roue de 28 sur l’axe horizontal est difficile à poser à cause de l’axe hexagonal et le peu d’espace, mais on y arrive en essayant d’enfoncer l’axe tout en le tournant un peu pour qu’il se positionne bien dans le trou hexagonal de la roue.</p>

<h3 id="05-soleil">05: Soleil</h3>

<p class="text-justify"><img src="/assets/images/tutos/038SoleilTerreLune/05_soleil.png" alt="Planétaire" class="align-left" />
Bien entendu pour le soleil vous pouvez sortir une bobine jaune. Tout comme les autres éléments pensez à bien poser la surface plate au sol avant d’imprimer les pièces, et imprimez les axes verticalement pour ne pas les déformer. Assemblez d’abord la partie haute et basse du soleil avec le petit axe de fixation, puis posez ce soleil de côté: vous le <strong>placerez en tout dernier</strong> sur la maquette. Vous pouvez renforcer la fixation des deux parties du Soleil en utilisant de la colle.</p>

<figure class="half ">
  
    
      <a href="/assets/images/tutos/038SoleilTerreLune/05_soleil_axe_assemblage_640.png">
          <img src="/assets/images/tutos/038SoleilTerreLune/05_soleil_axe_assemblage.png" alt="" />
      </a>
    
  
    
      <a href="/assets/images/tutos/038SoleilTerreLune/05_soleil_axe_640.png">
          <img src="/assets/images/tutos/038SoleilTerreLune/05_soleil_axe.png" alt="" />
      </a>
    
  
  
    <figcaption>Cliquez pour agrandir les images.
</figcaption>
  
</figure>

<p class="text-justify">Imprimez ensuite l’axe fixe interne et la petite collerette. La <strong>surface bombée</strong> de cette collerette doit se mettre en <strong>haut</strong>.</p>

<h3 id="06-révolution-terre">06: Révolution Terre</h3>

<p class="text-justify"><img src="/assets/images/tutos/038SoleilTerreLune/06_revolution_terre_300.png" alt="Planétaire" class="align-left" />
C’est parti pour imprimer l’engrenage qui permet de gérer la <strong>révolution de la Terre</strong> en <strong>365,256 jours</strong>. Si vous voulez savoir comment les roues dentées ont été calculées pour obtenir cette précision, tout est expliqué <a href="https://papsdroidfr.github.io/dev/CalculEngrenages/">dans cet article</a> avec un rappel théorique sur le calcul d’un rapport de réduction. J’ai opté pour imprimer les <strong>axes</strong> en noirs, et les roues dentées en blanc.</p>

<h4 id="engrenage-central">Engrenage central</h4>

<p class="text-justify"><img src="/assets/images/tutos/038SoleilTerreLune/06_revolution_terre_01_640.png" alt="Planétaire" class="align-center" />
Commencez par <strong>enlever le support haut de la base</strong>, puis imprimez tous les axes (en noir, à la verticale). L’axe creux de 10mm se positionne sur l’axe central rouge en veillant à bien mettre <strong>la collerette de l’axe vers le haut.</strong> Les 3 autres axes de 5mm ont 3 tailles différentes: chacune va dans son logement approprié (du plus petit au plus haut).</p>

<p class="text-justify">Imprimez ensuite les <strong>roues dentées</strong> en blanc ainsi que la <strong>collerette de 12mm</strong>: 3 roues de 16 dents, 1 roue de 40 dents et 2 roues de 82 dents. Si les roues sont dures à insérer sur les axes mettez un coup de cutter pour débarrasser les surplus de matière gênants. Positionnez les comme sur le dessin:</p>

<ul>
  <li><strong>sur le petit axe</strong>: une roue de 40 et la roue de 16 au dessus.</li>
  <li><strong>sur l’axe moyen</strong>: une roue de 82 et une roue de 16 au dessus.</li>
  <li><strong>sur le grand axe</strong>: une roue de 82, la collerette de 12mm et une roue de 16 au dessus.</li>
</ul>

<blockquote class="text-justify">
  <p>En tournant l’axe de la manivelle, la rotation des axes doit être fluide, sinon ébarbez avec un cutter ou un petit tournevis plat les surplus de matière qui gênent à l’intérieur des support des axes. Tout est calculé avec un jeux de 0,1mm pour que les axes ne partent pas dans tous les sens quand la rotation s’active.</p>
</blockquote>

<h4 id="roue-support-du-plateau">Roue support du plateau</h4>

<figure class="third ">
  
    
      <a href="/assets/images/tutos/038SoleilTerreLune/06_revolution_terre_02_640.png">
          <img src="/assets/images/tutos/038SoleilTerreLune/06_revolution_terre_02_300.png" alt="" />
      </a>
    
  
    
      <a href="/assets/images/tutos/038SoleilTerreLune/06_revolution_terre_03_640.png">
          <img src="/assets/images/tutos/038SoleilTerreLune/06_revolution_terre_03_300.png" alt="" />
      </a>
    
  
    
      <a href="/assets/images/tutos/038SoleilTerreLune/06_revolution_terre_04_640.png">
          <img src="/assets/images/tutos/038SoleilTerreLune/06_revolution_terre_04_300.png" alt="" />
      </a>
    
  
  
    <figcaption>Cliquez pour agrandir les images
</figcaption>
  
</figure>

<p class="text-justify">Vous pouvez <strong>remettre le support_haut de la base</strong>, et imprimez en blanc la collerette de 1mm ainsi que la grosse roue de 89 dents. N’oubliez surtout pas de positionner <strong>cette collerette de 1mm sous la roue</strong> de 89 dents.</p>

<blockquote class="text-justify">
  <p>Testez le mécanisme qui doit être parfaitement fluide lors de la rotation de la manivelle.</p>
</blockquote>

<h3 id="07-rotation-terre">07: Rotation Terre</h3>

<p class="text-justify"><img src="/assets/images/tutos/038SoleilTerreLune/07_rotation_terre_300.png" alt="Planétaire" class="align-left" />
L’engrenage qui va gérer la rotation de la Terre sur elle-même va être supporté par un plateau qui va tourner au même rythme que le mécanisme qui gère la révolution de la Terre. Ce plateau va évoluer sur un pied qui va glisser le long du plateau circulaire fabriqué lors des premières étapes.</p>

<figure class="half ">
  
    
      <a href="/assets/images/tutos/038SoleilTerreLune/07_rotation_terre_plateau_assemblage_640.png">
          <img src="/assets/images/tutos/038SoleilTerreLune/07_rotation_terre_plateau_assemblage_300.png" alt="" />
      </a>
    
  
    
      <a href="/assets/images/tutos/038SoleilTerreLune/07_rotation_terre_plateau_640.png">
          <img src="/assets/images/tutos/038SoleilTerreLune/07_rotation_terre_plateau_300.png" alt="" />
      </a>
    
  
  
    <figcaption>Cliquez pour agrandir les images
</figcaption>
  
</figure>

<p class="text-justify">Commencez par imprimer <strong>le plateau</strong> ainsi que le <strong>pied</strong> et les <strong>2 roues</strong>. Le plateau vient se fixer sur la grosse roue dentée de 89 dents de l’engrenage de la révolution de la Terre. <strong>Je conseille d’enlever cette roue</strong> pour la fixer sur le plateau en serrant fort (les encoches de la roue doivent être enfoncées au maximum sur le plateau), et de la remettre sur place avec son plateau bien fixé.</p>

<p class="text-justify"><img src="/assets/images/tutos/038SoleilTerreLune/07_rotation_terre_assemblage_640.png" alt="Planétaire" class="align-center" />
Vous pouvez ensuite imprimer les <strong>5 axes</strong> et <strong>6 roues dentées</strong> du mécanisme. <strong>Attention</strong> la toute première roue dentée de 29 dents (07_rotation_terre_gear29_axe_soleil) <strong>est différente</strong> des 3 autres roues de 29 dents (les dents n’ont pas le même profil). Ne vous mélangez surtout pas lorsqu’elles sont imprimées: <strong>sa place est sur l’axe central du Soleil</strong> (enlevez-le d’abord pour positionner cette roue). Les 3 petits axes sont identiques. Le grand axe est à reserver en bout de plateau pour l’axe de rotation de la Terre. Quand à l’axe moyen, il doit se positionner sur la 3ème roue comme sur la photo. Il va communiquer la rotation 1jour/tour au mécanisme de révolution de la Lune autour de la Terre.</p>

<blockquote class="text-justify">
  <p>Testez bien le mécanisme avant de passer à l’étape suivante: il doit être parfaitement fluide lors de la rotation de la manivelle. Si les roues du plateau ont tendance à sortir toutes seules de leur logement ce n’est pas grave: elles seront guidées par le plateau circulaire plus tard.</p>
</blockquote>

<h3 id="08-inclinaison-terre">08: Inclinaison Terre</h3>

<p class="text-justify"><img src="/assets/images/tutos/038SoleilTerreLune/08_inclinaison_terre_300.png" alt="Planétaire" class="align-left" />
Ce nouveau <strong>plateau</strong> avec ses <strong>3 roues dentées</strong> et <strong>2 axes</strong> vont permettre de gérer l’engrenage qui maintient l’axe incliné de la Terre dans la même position tout au long de sa révolution autour du Soleil. Pour cela notez bien que la roue de 92 dents doit être fixe sur l’axe sur soleil qui est fixe: c’est curieux mais le rôle de cette roue dentée est bien <strong>de ne pas tourner</strong>.</p>

<figure class="third ">
  
    
      <a href="/assets/images/tutos/038SoleilTerreLune/08_inclinaison_terre_01_640.png">
          <img src="/assets/images/tutos/038SoleilTerreLune/08_inclinaison_terre_01_300.png" alt="" />
      </a>
    
  
    
      <a href="/assets/images/tutos/038SoleilTerreLune/08_inclinaison_terre_02_640.png">
          <img src="/assets/images/tutos/038SoleilTerreLune/08_inclinaison_terre_02_300.png" alt="" />
      </a>
    
  
    
      <a href="/assets/images/tutos/038SoleilTerreLune/08_inclinaison_terre_03_640.png">
          <img src="/assets/images/tutos/038SoleilTerreLune/08_inclinaison_terre_03_300.png" alt="" />
      </a>
    
  
  
    <figcaption>Cliquez pour agrandir les images
</figcaption>
  
</figure>

<p class="text-justify">Positionnez d’abord le plateau et <strong>enfoncez bien les petits renforts</strong> qui servent à maintenir les plateaux ensembles. Imprimez ensuite les 2 axes (à la verticale) pour finir avec les 3 roues de 92 dents, 90 (au centre) et 92 à nouveau sur l’axe de la Terre. Les collerettes présentes sur les roues doivent être orientées vers le haut. Le montage suivant devrait ressembler à l’image ci-dessous.</p>
<p><img src="/assets/images/tutos/038SoleilTerreLune/08_inclinaison_terre_640.png" alt="Planétaire" class="align-center" /></p>

<h3 id="09-révolution-lune">09: Révolution Lune</h3>

<p class="text-justify"><img src="/assets/images/tutos/038SoleilTerreLune/09_revol_lune_300.png" alt="Planétaire" class="align-left" />
Nous enchaînons avec ce dernier plateau qui regroupe les 4 axes et 6 roues dentées qui vont gérer la <strong>révolution de la Lune</strong> en 27,32 jours autour de la Terre.</p>
<p><img src="/assets/images/tutos/038SoleilTerreLune/09_revol_lune_01_640.png" alt="Planétaire" class="align-center" />
<img src="/assets/images/tutos/038SoleilTerreLune/09_revol_lune_02_640.png" alt="Planétaire" class="align-center" />
<img src="/assets/images/tutos/038SoleilTerreLune/09_revol_lune_03_640.png" alt="Planétaire" class="align-center" /></p>

<p class="text-justify">Commencez par imprimer <strong>le plateau</strong> (en gris foncé) et insérez-le bien fermement au dessus du plateau précédents: les encoches doivent être clipsées à fond. Disposez ensuite les <strong>4 axes</strong> à imprimer en noir (à la verticale). Vous pouvez ensuite imprimer les <strong>6 roues dentées</strong>. J’ai imprimé la première de 13 dents en rouge car elle tourne à la vitesse de 1 jour par tour. Les autres roues peuvent s’imprimer en blanc.</p>
<p><img src="/assets/images/tutos/038SoleilTerreLune/09_revol_lune_dessus_640.png" alt="Planétaire" class="align-center" /></p>
<blockquote class="text-justify">
  <p>Assurez-vous bien que tous les mouvements soient bien fluides lorsque vous tournez la manivelle.</p>
</blockquote>

<h3 id="10-lune">10: Lune</h3>

<p class="text-justify"><img src="/assets/images/tutos/038SoleilTerreLune/10_lune_300.png" alt="Planétaire" class="align-left" />
La Lune est composée d’un plateau qui se fixe via un petit socle sur la roue de 81 dents du plateau précédent (il y a un petit renfort rectangulaire sur cette roue pour y fixer le plateau de la Lune) et de deux 1/2 sphères (lune_bas et lune_haut) à fixer sur l’axe vertical.</p>

<figure class="half ">
  
    
      <a href="/assets/images/tutos/038SoleilTerreLune/10_lune_01_640.png">
          <img src="/assets/images/tutos/038SoleilTerreLune/10_lune_01_300.png" alt="" />
      </a>
    
  
    
      <a href="/assets/images/tutos/038SoleilTerreLune/10_lune_02_640.png">
          <img src="/assets/images/tutos/038SoleilTerreLune/10_lune_02_640.png" alt="" />
      </a>
    
  
  
    <figcaption>Cliquez pour agrandir les images
</figcaption>
  
</figure>

<h3 id="11-terre">11: Terre</h3>

<p class="text-justify"><img src="/assets/images/tutos/038SoleilTerreLune/11_terre_300.png" alt="Planétaire" class="align-left" />
La Terre quand à elle se compose d’un <strong>plateau</strong>, de <strong>deux roues de 28 dents</strong> (attention elles ne sont pas identiques), <strong>une collerette</strong> , <strong>deux 1/2 sphères</strong> avec <strong>une fixation</strong> interne, et <strong>un axe</strong>. J’ai opté pour tout imprimer en bleu à l’exception des deux roues et la collerette que j’ai imprimées en rouge.</p>

<figure class="third ">
  
    
      <a href="/assets/images/tutos/038SoleilTerreLune/11_terre_01_640.png">
          <img src="/assets/images/tutos/038SoleilTerreLune/11_terre_01_300.png" alt="" />
      </a>
    
  
    
      <a href="/assets/images/tutos/038SoleilTerreLune/11_terre_02_640.png">
          <img src="/assets/images/tutos/038SoleilTerreLune/11_terre_02_300.png" alt="" />
      </a>
    
  
    
      <a href="/assets/images/tutos/038SoleilTerreLune/11_terre_03_640.png">
          <img src="/assets/images/tutos/038SoleilTerreLune/11_terre_03_640.png" alt="" />
      </a>
    
  
  
    <figcaption>Cliquez pour agrandir les images
</figcaption>
  
</figure>

<p class="text-justify">Le plateau se fixe au centre de la roue dentée. Attention à bien disposer la roue <strong>terre_gear28_axe_terre</strong> sur l’axe de la terre, et l’autre sur l’axe vertical au milieu de la roue de 81 dents.</p>

<h3 id="12-assemblage-final">12: Assemblage final</h3>

<p class="text-justify">A ce stade vous devriez avoir les deux parties ci-dessous: tout le mécanisme d’engrenage avec les plateaux et le socle circulaire sur ses pieds avec la manivelle.</p>

<figure class="half ">
  
    
      <a href="/assets/images/tutos/038SoleilTerreLune/12_assemblage_01_640.png">
          <img src="/assets/images/tutos/038SoleilTerreLune/12_assemblage_01_640.png" alt="" />
      </a>
    
  
    
      <a href="/assets/images/tutos/038SoleilTerreLune/12_assemblage_02_640.png">
          <img src="/assets/images/tutos/038SoleilTerreLune/12_assemblage_02_640.png" alt="" />
      </a>
    
  
  
    <figcaption>Cliquez pour agrandir les images
</figcaption>
  
</figure>

<p class="text-justify">Il suffit de les assembler en veillant à bien positionner <strong>l’axe de la roue rouge</strong> tout en bas des engrenages dans son logement sur le socle circulaire pour qu’elle soit positionnée <strong>juste au dessus de l’autre roue identique</strong> située sur la manivelle.</p>
<p><img src="/assets/images/tutos/038SoleilTerreLune/12_assemblage_640.png" alt="Planétaire" class="align-center" /></p>

<blockquote class="text-justify">
  <p>Cette maquette est maintenant terminée, il y a un logement pour un moteur (au dessus de la manivelle), un autre article va détailler la motorisation électronique de tout le mécanisme. En attendant elle est parfaitement fonctionnelle, chaque tour de manivelle représentant une journée.</p>
</blockquote>

<h2 id="médias">Médias</h2>

<figure class="third ">
  
    
      <a href="/assets/images/tutos/038SoleilTerreLune/13_planetaire_01_640.png">
          <img src="/assets/images/tutos/038SoleilTerreLune/13_planetaire_01_640.png" alt="" />
      </a>
    
  
    
      <a href="/assets/images/tutos/038SoleilTerreLune/13_planetaire_02_640.png">
          <img src="/assets/images/tutos/038SoleilTerreLune/13_planetaire_02_640.png" alt="" />
      </a>
    
  
    
      <a href="/assets/images/tutos/038SoleilTerreLune/13_planetaire_03_640.png">
          <img src="/assets/images/tutos/038SoleilTerreLune/13_planetaire_03_640.png" alt="" />
      </a>
    
  
  
</figure>

<figure class="third ">
  
    
      <a href="/assets/images/tutos/038SoleilTerreLune/13_planetaire_04_640.png">
          <img src="/assets/images/tutos/038SoleilTerreLune/13_planetaire_04_640.png" alt="" />
      </a>
    
  
    
      <a href="/assets/images/tutos/038SoleilTerreLune/13_planetaire_05_640.png">
          <img src="/assets/images/tutos/038SoleilTerreLune/13_planetaire_05_640.png" alt="" />
      </a>
    
  
    
      <a href="/assets/images/tutos/038SoleilTerreLune/13_planetaire_06_640.png">
          <img src="/assets/images/tutos/038SoleilTerreLune/13_planetaire_06_640.png" alt="" />
      </a>
    
  
  
    <figcaption>Cliquez pour agrandir les images
</figcaption>
  
</figure>

<!-- Courtesy of embedresponsively.com -->

<div class="responsive-video-container">
    <iframe src="https://www.youtube-nocookie.com/embed/fjxmEh7h7ck" frameborder="0" webkitallowfullscreen="" mozallowfullscreen="" allowfullscreen=""></iframe>
  </div>

<h2 id="motorisation">Motorisation</h2>

<p class="text-justify"><img src="/assets/images/tutos/038SoleilTerreLune/IMG_webserver_montage_640.jpg" alt="Planétaire" class="align-center" />
Si vous savez souder des composants électroniques sur une carte PCB, vous pouvez motoriser ce planétaire avec un peu d’électronique bon marché et facilement accessible. Ce circuit va générer un petit serveur WEB local accessible depuis votre smartphone. Le moteur se positionne tout simplement sur son support: une petite encoche dans l’ouverture permet d’identifier où se trouve le méplat pour pouvoir faire rentrer l’axe du moteur à travers l’axe de la manivelle.</p>

<p class="text-justify">La notice de montage est disponible sur <a href="https://github.com/papsdroidfr/WebServerPlanetaire">ce Github</a>.</p>

<blockquote class="text-justify">
  <p>J’ai plusieurs PCB d’avance à ma disposition: vous pouvez me contactez si vous souhaitez en récupérer un.</p>
</blockquote>]]></content><author><name>PapsDroid</name><email>papsdroid.fr@gmail.com</email></author><category term="tutoriels" /><category term="planétaire" /><summary type="html"><![CDATA[Cet article détaille l'assemblage d'un planétaire mécanique du système Soleil Terre Lune, entièrement imprimé 3D, avec en option la motorisation du système]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://papsdroidfr.github.io//assets/images/tutos/038SoleilTerreLune/header.jpeg" /><media:content medium="image" url="https://papsdroidfr.github.io//assets/images/tutos/038SoleilTerreLune/header.jpeg" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Veilleuse ESP32</title><link href="https://papsdroidfr.github.io//tutoriels/veilleuse/" rel="alternate" type="text/html" title="Veilleuse ESP32" /><published>2024-03-18T00:00:00+00:00</published><updated>2024-03-18T00:00:00+00:00</updated><id>https://papsdroidfr.github.io//tutoriels/veilleuse</id><content type="html" xml:base="https://papsdroidfr.github.io//tutoriels/veilleuse/"><![CDATA[<p class="text-justify"><img src="/assets/images/tutos/037ESP32Veilleuse/veilleuse_300.jpg" alt="Veilleuse" class="align-left" />
Ce projet permet de construire une petite veilleuse sympathique imprimée 3D qui contrôle un petit anneau de 12 leds RGB 5v avec un ESP32. Cette veilleuse très sobre en énergie va consommer à peine 1.2 watts en fonctionnement, avec une animation au démarrage suivie d’un effet de léger crépitement comme un feu de bougie.</p>

<h2 id="hardware">Hardware</h2>

<h3 id="matériel">Matériel</h3>

<p>Pour seul matériel, il faut:</p>

<ul>
  <li>1 <a href="https://www.az-delivery.de/fr/products/esp32-d1-mini">ESP32 MINI D1</a> d’AZ-Delivery (tout autre ESP32 nécessitera d’adapter le socle de la veilleuse imprimé 3D)</li>
  <li>1 petit anneau de <a href="https://www.az-delivery.de/fr/products/rgb-led-ring-ws2812-mit-12-rgb-leds-5v-fuer-arduino">12 leds RGB WS2812B</a> 5V, 37mm  comme ceux qu’on trouve chez AZ-delivery</li>
  <li>3 petits câbles en fil dur à souder</li>
  <li>1 alimentation 5v micro-usb avec bouton on/off: un modèle 15w pour alimenter un raspberry-pi 3 avec bouton on/off sera parfait.</li>
</ul>

<p>rien de plus !</p>

<h3 id="assemblage">assemblage</h3>

<p class="text-justify"><img src="/assets/images/tutos/037ESP32Veilleuse/assemblage.jpg" alt="Veilleuse" />
à l’aide de 3 fils à souder durs (pour maintenir l’anneau au dessus de l’ESP32 il est important d’utiliser des fils durs), reliez comme sur l’image:</p>

<ul>
  <li>VCC +5V de l’ESP32 au VCC de l’anneau</li>
  <li>GND de l’ESP32 au GND de l’anneau</li>
  <li>GPIO16 de l’ESP32 au IN de l’anneau</li>
</ul>

<h3 id="impression-3d">Impression 3D</h3>

<p class="text-justify">Le modèle de base à imprimer est disponible et gratuit sur Thingiverse. Il s’agit de cet <a href="https://www.thingiverse.com/thing:3939396">hibou rigolo</a>. J’ai retravaillé le socle afin de pouvoir y loger l’ESP32 au format carré ainsi que le cordon d’alimentation micro-usb: le socle de base ne le permet pas.</p>
<ul class="text-justify">
  <li>Imprimez-donc le hibou du modèle de base <strong>avec un PLA translucide</strong>. Je conseille une hauteur de couche à 0,15mm pour avoir une belle définition des détails. L’usage des supports est obligatoire. un PLA translucide permettra de laisser passer la lumière.</li>
</ul>

<ul class="text-justify">
  <li>Imprimez ensuite le socle modifié que je mets à dispostion sur mon <a href="https://github.com/papsdroidfr/ESP32_Veilleuse">Github</a>, dans la section <strong>/STL</strong>. une hauteur de couche en 0.3mm est suffisante pour le socle, et pas besoin de support.</li>
</ul>

<p><img src="/assets/images/tutos/037ESP32Veilleuse/socle.jpg" alt="Veilleuse" /></p>

<h2 id="software">Software</h2>

<h3 id="configuration-esp32">configuration ESP32</h3>

<p class="text-justify">Il faut dans un premier temps flasher la dernière version de micro-python sur l’ESP32 à l’aide de l’IDE <a href="https://thonny.org/">Thonny</a>. L’opération est très simple et se passe en 4 temps:</p>
<ul class="text-justify">
  <li>téléchargez la dernier <strong>firmware</strong> (c’est un fichier .bin) de <a href="https://micropython.org/download/ESP32_GENERIC/">micro-python pour ESP32</a> sur le site officiel micro-python. Pas besoin d’installer esptool , Thonny sait comment flasher un firmware sur un ESP32 relié par USB sur l’ordinateur. A l’heure où j’écris ces lignes, j’ai téléchargé la version v1.22.2(2024-02-22).bin</li>
</ul>
<ul class="text-justify">
  <li>Ouvrez Thonny, et connectez l’ESP32 à l’ordinateur  à l’aide d’un cable USB.</li>
</ul>
<ul class="text-justify">
  <li>Allez dans Outils -&gt; Options -&gt; Interpréteurs et choisir “MicroPython (ESP32)”, puis cliquer sur “Installer ou mettre à jour le firmware”</li>
</ul>
<ul class="text-justify">
  <li>choisir le port dans la liste déroulante (normalement le bon port est reconnu dès le branchement de l’ESP32), puis sélectionnez l’image .bin téléchargée sur votre ordinateur.</li>
</ul>
<p class="text-justify">Après une minute ou deux de mise à jour, ça y est le flash micropython sur l’ESP32 est prêt.</p>

<h3 id="script-micropython">script micropython</h3>

<p class="text-justify">Le script principal <strong>main.py</strong> est à récupérer sur le <a href="https://github.com/papsdroidfr/ESP32_Veilleuse">Github du projet</a> dans la section <strong>/micropython</strong>. Il va lancer une petite animation qui dure quelques secondes et ensuite basculer sur une couleur avec un petit effet de crépitement.</p>

<p>Si vous souhaitez modifier la couleur (dans mon script j’utilise du violet = 50% bleu  + 50% rouge) il suffit d’adapter la ligne 39</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code>        <span class="k">for</span> <span class="n">j</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="n">n</span><span class="p">):</span>
            <span class="n">np</span><span class="p">[</span><span class="n">j</span><span class="p">]</span> <span class="o">=</span> <span class="p">(</span><span class="mi">128</span><span class="o">+</span><span class="n">delta</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">128</span><span class="o">+</span><span class="n">delta</span><span class="p">)</span>
</code></pre></div></div>
<p class="text-justify">la varialbe <strong>delta</strong> sert à simuler le crépitement. (128, 0, 128) représente du violet: mettez ce que vous voulez comme couleur sans oublier d’y rajouter +delta pour simuler le crépitement. Par exemple si vous voulez du vert: (0,128+delta,0) fera l’affaire. Ou bien (0,0,128+delta) pour du bleu, ou encore (0, 128+delta, 128+delta) pour obtenir du jaune (vert + bleu) etc … On peut simuler 65 millions de couleurs comme ça.</p>

<!-- Courtesy of embedresponsively.com -->

<div class="responsive-video-container">
    <iframe src="https://www.youtube-nocookie.com/embed/YkUEj5xpYDk" frameborder="0" webkitallowfullscreen="" mozallowfullscreen="" allowfullscreen=""></iframe>
  </div>]]></content><author><name>PapsDroid</name><email>papsdroid.fr@gmail.com</email></author><category term="tutoriels" /><category term="micro-python" /><category term="ESP32" /><category term="ruban leds" /><summary type="html"><![CDATA[Une veilleuse à base d'un ESP32 et d'un petit anneau de leds]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://papsdroidfr.github.io//assets/images/tutos/036ESP32meteo/boitier3D_300.jpg" /><media:content medium="image" url="https://papsdroidfr.github.io//assets/images/tutos/036ESP32meteo/boitier3D_300.jpg" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Meteo Connect</title><link href="https://papsdroidfr.github.io//tutoriels/meteo-connect/" rel="alternate" type="text/html" title="Meteo Connect" /><published>2023-03-18T00:00:00+00:00</published><updated>2023-03-18T00:00:00+00:00</updated><id>https://papsdroidfr.github.io//tutoriels/meteo-connect</id><content type="html" xml:base="https://papsdroidfr.github.io//tutoriels/meteo-connect/"><![CDATA[<p class="text-justify"><img src="/assets/images/tutos/036ESP32meteo/boitier3D_300.png" alt="MeteoCOnnect" class="align-left" />
Ce projet détaille pas à pas la construction d’une petite station météo de salon connectée, à base d’un <a href="https://papsdroidfr.github.io/configuration/Pybstick-C3/">ESP32-C3</a> made in France. Un capteur de température interne DHT22, qui sera calibré par le logiciel, permet d’afficher la température et l’humidité de la pièce dans laquelle il fonctionne, tandis que les données météorologiques externes sont collectées sur internet en WIFI par un appel d’API. Le tout est affiché sur un petit écran LCD composé de 2 lignes, 16 caractères. L’électronique est logée dans un petit boîtier sur mesure, à imprimer en 3D.</p>

<h2 id="hardware">Hardware</h2>

<h3 id="matériel">Matériel</h3>

<p><img src="/assets/images/tutos/036ESP32meteo/materiel.jpg" alt="MeteoCOnnect" class="align-center" /></p>

<p>pour ce projet il faut:</p>

<ul class="text-justify">
  <li>1 <a href="https://shop.mchobby.be/fr/pybstick/2505-pybstick26-esp32-c3-micropython-et-arduino-3232100025059.html">PYBSTICK ESP32-C3</a> micro-usb avec les 2 rangées de pin headers 13 broches soudées. Cet ESP32-C3 est fabriqué en France.</li>
</ul>
<ul class="text-justify">
  <li>1 PCB que vous pouvez faire fabriquer à partir des fichier Gerber fourni dans la section <strong>/PCB</strong> du <a href="https://github.com/papsdroidfr/MeteoConnect">Github du projet</a>, ou bien me contacter pour savoir s’il m’en reste en stock.</li>
</ul>
<ul class="text-justify">
  <li>1 écran LCD 16*02 avec backpack I2C</li>
</ul>
<ul class="text-justify">
  <li>4 fils souples connecteurs dupont mâle-mâle pour relier le PCB à l’écran LCD.</li>
</ul>
<ul class="text-justify">
  <li>1 connecteur coudé 4 pin 2.54mm à souder</li>
</ul>
<ul class="text-justify">
  <li>1 capteur de température et humidité DHT22 avec 4 broches</li>
</ul>
<ul class="text-justify">
  <li>1 diode Schottky SR560</li>
</ul>
<ul class="text-justify">
  <li>1 résistance 10KΩ</li>
</ul>
<ul class="text-justify">
  <li>1 condensateur céramique 100nf</li>
</ul>
<ul class="text-justify">
  <li>1 prise jack DC 3 pin à souder</li>
</ul>
<ul class="text-justify">
  <li>1 alimentation 5v 2A avec prise Jack</li>
</ul>
<ul class="text-justify">
  <li>4 entretoises M2.5 15mm en nylon, femelle-mâle</li>
</ul>
<ul class="text-justify">
  <li>4 entretoise M2.5 6mm en nylon, femelle-mâle</li>
</ul>
<ul class="text-justify">
  <li>1 boîtier à imprimer 3D, les STL sont à récupérer dans la section <strong>/STL</strong> du <a href="https://github.com/papsdroidfr/MeteoConnect">Github du projet</a>.</li>
</ul>

<h3 id="électronique">Électronique</h3>

<p class="text-justify"><img src="/assets/images/tutos/036ESP32meteo/PCB_assemblage.jpg" alt="MeteoCOnnect" class="align-center" />
La photo ci-dessus illustre les soudures à faire sur le PCB. Les instructions sont clairement sérigraphiées sur la carte. Ne vous trompez surtout pas de sens avec la PYPSTICK ESP32-C3 ainsi que la diode Schottky.</p>

<h3 id="assemblage">Assemblage</h3>

<figure class="third ">
  
    
      <img src="/assets/images/tutos/036ESP32meteo/assemblage1.jpg" alt="" />
    
  
    
      <img src="/assets/images/tutos/036ESP32meteo/assemblage2.jpg" alt="" />
    
  
    
      <img src="/assets/images/tutos/036ESP32meteo/assemblage3.jpg" alt="" />
    
  
  
    <figcaption>
</figcaption>
  
</figure>

<p class="text-justify">Le boîtier est composé d’une partie basse dans laquelle se loge le circuit rehaussé avec les entretoises M2.5 en nylon (mettre les petites de 6mm en dessous, elles se vissent sur les grandes de 15mm qui vont supporter l’écran LCD.). La partie haute se clipse autour du LCD correctement positionné sur les entretoises 15mm. Il faut couper au cutter à raz bord du PCB les vis mâles en nylon qui dépassent pour pouvoir fermer le boîtier.</p>
<p class="text-justify">Deux pieds inclinés (à coller avec de la colle PVC) peuvent se mettre sous le boîtier afin de faciliter la lecture de l’écran lorsqu’il est posé sur une table.</p>

<h2 id="software">Software</h2>

<h3 id="scripts-micropython">scripts micropython</h3>

<p>Tous les scripts sont à récupérer dans la section /micropython du <a href="https://github.com/papsdroidfr/MeteoConnect">Github du projet</a></p>

<ul class="text-justify">
  <li><a href="https://papsdroidfr.github.io/dev/ESP32-LCD/">Cet article</a> explique le fonctionnement d’un écran LCD avec un ESP32-C3</li>
</ul>
<ul class="text-justify">
  <li><a href="https://papsdroidfr.github.io/dev/ESP32-DHT22/">Cet article</a> explique comment utiliser un DHT22 avec un ESP32-C3</li>
</ul>
<ul class="text-justify">
  <li><a href="https://papsdroidfr.github.io/dev/meteoESP32/">Cet article</a> détaille l’utilisation d’une API de météo avec l’ESP32-C3 afin de récupérer par WIFI les données météorologiques extérieures.</li>
</ul>

<p class="text-justify">N’oubliez pas de <strong>mettre à jour quelques paramètres</strong> dans les scripts ci-dessous, en remplaçant les valeurs ‘xxxxx’:</p>

<ul class="text-justify">
  <li><strong>boot.py</strong>: indiquez votre WIFI_SSID et WIFI_PASSWORD pour que le boîtier se connecte à internet via votre WIFI</li>
</ul>
<ul class="text-justify">
  <li><strong>api_meteo.py</strong>: indiquez votre TOKEN de connection à l’API comme expliqué dans <a href="https://papsdroidfr.github.io/dev/meteoESP32/">cet article</a>.</li>
</ul>

<h3 id="calibration-du-capteur">Calibration du capteur</h3>

<p class="text-justify"><img src="/assets/images/tutos/036ESP32meteo/qualibrate.jpg" alt="MeteoCOnnect" class="align-left" />
Le DHT22 est un capteur sensible, il suffit de s’en approcher pour voir immédiatement quelques dixièmes de degrés supplémentaires apparaître. Comme il est soudé sur la carte, l’électronique à proximité va perturber les mesures bien que l’ESP32-C3 soit sobre en consommation: rien ne chauffe. Malgré tout, une petite dérive s’installe et il faut procéder à une calibration pour compenser cette dérive.</p>

<h4 id="principe">Principe</h4>

<p class="text-justify">Il faudra vous équiper d’un thermomètre de référence, de préférence un tout simple non électronique au mercure. Le principe est de prendre <strong>2 mesures assez éloignées</strong>  avec 4 ou 5°C d’écart (une dans la pièce courante, et une à
l’extérieur). Ensuite la calibration consiste à faire une interpolation linéaire à partir de ces 2 mesures.</p>

<h4 id="procédure">Procédure</h4>

<ul class="text-justify">
  <li>Il faut tout d’abord <strong>régler sur Off la calibration</strong> (elle est sur On par défaut avec mes propres mesures): dans le programme dht22.py mettez la variable en ligne 6  <strong>QUALIBRATION = False</strong> (à la place de QUALIBRATION=True)</li>
</ul>
<ul class="text-justify">
  <li>Ensuite prenez vos deux mesures éloignées de quelques degrès, attendez bien à chaque fois un bon 1/4 d’h pour que les mesures soient stabilisées. Notez-les (T_DHT1, T_R1) et (T_DHT2, T_R2), T_DHTx étant la température indiquée par le DHT22, et T_Rx étant celle indiquée par votre thermomètre de référence.</li>
</ul>
<ul class="text-justify">
  <li>Reportez les valeurs dans le programme dht22.py, lignes 7 à 10, et remettez la variable QUALIBRATION = True en ligne 6</li>
</ul>

<p class="text-justify">Le programme va alors calibrer la température T mesurée par le DHT22 selon cette formule:</p>

<pre><code class="language-maths">Tc  =  r * T + T0
r = (T_R2 - T_R1) / (T_DHT2 - T_DHT1)
T0 = TR2 - r * T_DHT2
</code></pre>

<blockquote class="text-justify">
  <p>Et voilà la calibration est terminée: la température affichée par le DHT22 devrait être équivalente à celle du thermomètre de référence dans vote pièce principale.</p>
</blockquote>

<h2 id="usage">Usage</h2>

<figure class="third ">
  
    
      <img src="/assets/images/tutos/036ESP32meteo/ecran1.jpg" alt="" />
    
  
    
      <img src="/assets/images/tutos/036ESP32meteo/ecran2.jpg" alt="" />
    
  
    
      <img src="/assets/images/tutos/036ESP32meteo/ecran3.jpg" alt="" />
    
  
  
    <figcaption>
</figcaption>
  
</figure>

<p class="text-justify">La première ligne donne les valeurs du capteur interne DHT22: température et humidité. Ces valeurs sont mises à jour toutes les 5 secondes.</p>

<p class="text-justify">La seconde ligne affiche les données météorologiques externes récupérées sur internet et mises à jour toutes les 5 minutes.</p>

<ul class="text-justify">
  <li>dans un premier temps on affiche la température externe et le taux d’humidité</li>
</ul>
<ul class="text-justify">
  <li>ensuite il s’affiche la vitesse du vent et la probabilité qu’il pleuve</li>
</ul>
<ul class="text-justify">
  <li>Enfin le bulletin météorologique est scrollé à l’écran.</li>
</ul>]]></content><author><name>PapsDroid</name><email>papsdroid.fr@gmail.com</email></author><category term="tutoriels" /><category term="pybstick" /><category term="micro-python" /><category term="ESP32" /><category term="écran LCD" /><category term="DHT22" /><summary type="html"><![CDATA[Météo de salon connectée pilotée par un ESP32-C3]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://papsdroidfr.github.io//assets/images/tutos/036ESP32meteo/boitier3D_300.png" /><media:content medium="image" url="https://papsdroidfr.github.io//assets/images/tutos/036ESP32meteo/boitier3D_300.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">ESP32 et écran LCD</title><link href="https://papsdroidfr.github.io//dev/ESP32-LCD/" rel="alternate" type="text/html" title="ESP32 et écran LCD" /><published>2023-01-21T00:00:00+00:00</published><updated>2023-01-21T00:00:00+00:00</updated><id>https://papsdroidfr.github.io//dev/ESP32-LCD</id><content type="html" xml:base="https://papsdroidfr.github.io//dev/ESP32-LCD/"><![CDATA[<p class="text-justify"><img src="/assets/images/tutos/036ESP32meteo/lcd.jpg" alt="ESP32-LCD" class="align-left" />
Un écran LCD avec un backpack I2C est très simple à utiliser avec un ESP32 sous micropython. On peut y afficher du texte et aussi quelques logos personnalisés en définition 5x8 pixels. Dans ce tuto j’utilise un LCD (avec backpack I2C) de 2 lignes de 16 caractères, et le microcontrôleur made in France <a href="https://papsdroidfr.github.io/configuration/Pybstick-C3/">PYBSTICK ESP32-C3</a>. En fonction du microcontrôleur que vous utilisez, seul le schéma électronique doit être adapté.</p>

<h2 id="circuit-électronique">Circuit électronique</h2>
<p class="text-justify"><img src="/assets/images/tutos/036ESP32meteo/ESP32-LCD_fritzing.png" alt="ESP32-LCD" class="align-center" />
Très simple: il faut relier VCC au +5V, GND à la masse, et SDA et SCL aux entrées soft I2C SDA et SCL de votre ESP32.</p>

<h2 id="code-micropython">Code micropython</h2>

<h3 id="bibliothèques">Bibliothèques</h3>
<p class="text-justify">Pour pouvoir gérer l’écran LCD via I2C, il faut tout d’abord installer ces deux bibliothèques sur votre ESP32: copiez/collez le code micropython de ces 2 programmes, et nommez les exactement comme sur cette source Github:</p>
<ul class="text-justify">
  <li><a href="https://peppe8o.com/download/micropython/LCD/lcd_api.py">lcd_api.py</a></li>
  <li><a href="https://peppe8o.com/download/micropython/LCD/i2c_lcd.py">i2c_lcd.py</a></li>
</ul>

<h3 id="afficher-un-logo">Afficher un logo</h3>
<p class="text-justify">Nous pouvons définir 8 petits logos personnalisés 5x8 pixels à l’aide d’un tableau de 8 codes hexadécimaux (8 lignes) qui codent les 5 pixels de chaque ligne. Il y a cet outil en ligne <a href="https://maxpromer.github.io/LCD-Character-Creator/">LCD Character Creator</a> très pratique pour dessiner à l’écran votre logo et récupérer les codes hexadécimaux correspondants. Utilisez bien <strong>Data Type = Hex</strong> (et non pas Binary) pour récupérer les <strong>codes Hexa</strong>.</p>
<p class="text-justify"><img src="/assets/images/tutos/036ESP32meteo/Character_LCD_Creator.png" alt="ESP32-LCD" class="align-center" />
Si vous créez ce logo de robot, vous devriez obtenir cette liste de 8 codes hexa: <strong>0x0E,  0x1F,  0x15,  x1F,  0x1F,  0x11,  0x1F,  0x0E</strong></p>

<h3 id="code-micropython-1">code micropython</h3>

<p class="text-justify">Le code ci-dessous défini une classe LCD dans laquelle des logos perso sont définis dans un dictionnaire de logos <strong>dic_char</strong>. C’est ici que l’on recopie les codes hexadécimaux récupérés depuis l’outil LCD Character Creator.</p>
<ul class="text-justify">
  <li><strong>dic_char</strong>: dictionnaire des logo {‘nom du logo’: ( id_logo de 0 à 7 , [liste des codes hexadécimaux] ) }</li>
</ul>
<ul class="text-justify">
  <li><strong>get_char(self, name:str) -&gt;chr</strong>: retourne un logo à partir de son nom.</li>
</ul>
<ul class="text-justify">
  <li><strong>scroll(self, s:str, lig:int, col:int)</strong>: scroll un texte de droite à gauche jusqu’en position (lig, col).</li>
</ul>
<ul class="text-justify">
  <li><strong>get_i2c(self, sda_pin:int, scl_pin:int) -&gt;SoftI2C</strong> : retourne l’adresse I2C du LCD branché sur les pin sda_pin et scl-pin. En cas de mauvais branchement, des messages d’erreur sont affichés dans la console si vous exécutez ce programme depuis un ordi.</li>
</ul>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">from</span> <span class="nn">machine</span> <span class="kn">import</span> <span class="n">Pin</span><span class="p">,</span> <span class="n">SoftI2C</span>
<span class="kn">from</span> <span class="nn">lcd_api</span> <span class="kn">import</span> <span class="n">LcdApi</span>
<span class="kn">from</span> <span class="nn">i2c_lcd</span> <span class="kn">import</span> <span class="n">I2cLcd</span>
<span class="kn">from</span> <span class="nn">time</span> <span class="kn">import</span> <span class="n">sleep</span>
<span class="kn">from</span> <span class="nn">sys</span> <span class="kn">import</span> <span class="nb">exit</span>

<span class="n">I2C_ADDR</span> <span class="o">=</span> <span class="mh">0x27</span>
<span class="n">SDA_PIN</span> <span class="o">=</span> <span class="mi">0</span>
<span class="n">SCL_PIN</span> <span class="o">=</span> <span class="mi">1</span>
<span class="n">TOTAL_ROWS</span> <span class="o">=</span> <span class="mi">2</span>
<span class="n">TOTAL_COLUMNS</span> <span class="o">=</span> <span class="mi">16</span>

<span class="k">class</span> <span class="nc">LCD</span><span class="p">(</span><span class="n">I2cLcd</span><span class="p">):</span>
    <span class="k">def</span> <span class="nf">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">sda_pin</span><span class="p">:</span><span class="nb">int</span><span class="o">=</span><span class="n">SDA_PIN</span><span class="p">,</span> <span class="n">scl_pin</span><span class="p">:</span><span class="nb">int</span><span class="o">=</span><span class="n">SCL_PIN</span><span class="p">):</span>
        <span class="s">""" constructor """</span>
        <span class="bp">self</span><span class="p">.</span><span class="n">i2c</span> <span class="o">=</span> <span class="bp">self</span><span class="p">.</span><span class="n">get_i2c</span><span class="p">(</span><span class="n">sda_pin</span><span class="p">,</span> <span class="n">scl_pin</span><span class="p">)</span>
        <span class="k">if</span> <span class="bp">self</span><span class="p">.</span><span class="n">i2c</span> <span class="ow">is</span> <span class="ow">not</span> <span class="bp">None</span><span class="p">:</span>
            <span class="n">I2cLcd</span><span class="p">.</span><span class="n">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="bp">self</span><span class="p">.</span><span class="n">i2c</span><span class="p">,</span> <span class="n">I2C_ADDR</span><span class="p">,</span> <span class="n">TOTAL_ROWS</span><span class="p">,</span> <span class="n">TOTAL_COLUMNS</span><span class="p">)</span>
            <span class="bp">self</span><span class="p">.</span><span class="n">clear</span><span class="p">()</span>
            
            <span class="c1"># generator custom character: https://maxpromer.github.io/LCD-Character-Creator/        
</span>            <span class="bp">self</span><span class="p">.</span><span class="n">dic_char</span><span class="o">=</span><span class="p">{</span><span class="s">'wifi'</span>       <span class="p">:</span> <span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="nb">bytearray</span><span class="p">([</span><span class="mh">0x0E</span><span class="p">,</span> <span class="mh">0x11</span><span class="p">,</span> <span class="mh">0x00</span><span class="p">,</span> <span class="mh">0x1F</span><span class="p">,</span> <span class="mh">0x00</span><span class="p">,</span> <span class="mh">0x0E</span><span class="p">,</span> <span class="mh">0x00</span><span class="p">,</span> <span class="mh">0x04</span><span class="p">])</span> <span class="p">),</span>
                           <span class="s">'thermometre'</span><span class="p">:</span> <span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="nb">bytearray</span><span class="p">([</span><span class="mh">0x04</span><span class="p">,</span> <span class="mh">0x0B</span><span class="p">,</span> <span class="mh">0x0A</span><span class="p">,</span> <span class="mh">0x0B</span><span class="p">,</span> <span class="mh">0x0A</span><span class="p">,</span> <span class="mh">0x17</span><span class="p">,</span> <span class="mh">0x1F</span><span class="p">,</span> <span class="mh">0x0E</span><span class="p">])</span> <span class="p">),</span> 
                           <span class="s">'soleil'</span>     <span class="p">:</span> <span class="p">(</span><span class="mi">2</span><span class="p">,</span> <span class="nb">bytearray</span><span class="p">([</span><span class="mh">0x00</span><span class="p">,</span> <span class="mh">0x15</span><span class="p">,</span> <span class="mh">0x0E</span><span class="p">,</span> <span class="mh">0x11</span><span class="p">,</span> <span class="mh">0x11</span><span class="p">,</span> <span class="mh">0x11</span><span class="p">,</span> <span class="mh">0x0E</span><span class="p">,</span> <span class="mh">0x15</span><span class="p">])</span> <span class="p">),</span>
                           <span class="s">'pluie'</span>      <span class="p">:</span> <span class="p">(</span><span class="mi">3</span><span class="p">,</span> <span class="nb">bytearray</span><span class="p">([</span><span class="mh">0x15</span><span class="p">,</span> <span class="mh">0x00</span><span class="p">,</span> <span class="mh">0x0E</span><span class="p">,</span> <span class="mh">0x1F</span><span class="p">,</span> <span class="mh">0x04</span><span class="p">,</span> <span class="mh">0x04</span><span class="p">,</span> <span class="mh">0x14</span><span class="p">,</span> <span class="mh">0x08</span><span class="p">])</span> <span class="p">),</span>
                           <span class="s">'nuages'</span>     <span class="p">:</span> <span class="p">(</span><span class="mi">4</span><span class="p">,</span> <span class="nb">bytearray</span><span class="p">([</span><span class="mh">0x03</span><span class="p">,</span> <span class="mh">0x0F</span><span class="p">,</span> <span class="mh">0x1E</span><span class="p">,</span> <span class="mh">0x1E</span><span class="p">,</span> <span class="mh">0x0C</span><span class="p">,</span> <span class="mh">0x00</span><span class="p">,</span> <span class="mh">0x00</span><span class="p">,</span> <span class="mh">0x00</span><span class="p">])</span> <span class="p">),</span>
                           <span class="s">'neige'</span>      <span class="p">:</span> <span class="p">(</span><span class="mi">5</span><span class="p">,</span> <span class="nb">bytearray</span><span class="p">([</span><span class="mh">0x10</span><span class="p">,</span> <span class="mh">0x05</span><span class="p">,</span> <span class="mh">0x02</span><span class="p">,</span> <span class="mh">0x05</span><span class="p">,</span> <span class="mh">0x00</span><span class="p">,</span> <span class="mh">0x14</span><span class="p">,</span> <span class="mh">0x08</span><span class="p">,</span> <span class="mh">0x14</span><span class="p">])</span> <span class="p">),</span>
                           <span class="s">'brouillard'</span> <span class="p">:</span> <span class="p">(</span><span class="mi">6</span><span class="p">,</span> <span class="nb">bytearray</span><span class="p">([</span><span class="mh">0x0E</span><span class="p">,</span> <span class="mh">0x1F</span><span class="p">,</span> <span class="mh">0x0A</span><span class="p">,</span> <span class="mh">0x15</span><span class="p">,</span> <span class="mh">0x0A</span><span class="p">,</span> <span class="mh">0x15</span><span class="p">,</span> <span class="mh">0x0A</span><span class="p">,</span> <span class="mh">0x15</span><span class="p">])</span> <span class="p">),</span>
                           <span class="s">'papsdroid'</span>  <span class="p">:</span> <span class="p">(</span><span class="mi">7</span><span class="p">,</span> <span class="nb">bytearray</span><span class="p">([</span><span class="mh">0x0E</span><span class="p">,</span> <span class="mh">0x1F</span><span class="p">,</span> <span class="mh">0x15</span><span class="p">,</span> <span class="mh">0x1F</span><span class="p">,</span> <span class="mh">0x1F</span><span class="p">,</span> <span class="mh">0x11</span><span class="p">,</span> <span class="mh">0x1F</span><span class="p">,</span> <span class="mh">0x0E</span><span class="p">])</span> <span class="p">),</span>
                           <span class="p">}</span>
            <span class="k">for</span> <span class="n">__cle</span><span class="p">,</span> <span class="n">val</span> <span class="ow">in</span> <span class="bp">self</span><span class="p">.</span><span class="n">dic_char</span><span class="p">.</span><span class="n">items</span><span class="p">():</span>
                <span class="bp">self</span><span class="p">.</span><span class="n">custom_char</span><span class="p">(</span><span class="n">val</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="n">val</span><span class="p">[</span><span class="mi">1</span><span class="p">])</span>
            
        <span class="k">else</span><span class="p">:</span>
            <span class="k">print</span><span class="p">(</span><span class="s">'Revoir branchements écran LCD'</span><span class="p">)</span>
            <span class="nb">exit</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>
          
    <span class="k">def</span> <span class="nf">get_char</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">name</span><span class="p">:</span><span class="nb">str</span><span class="p">)</span> <span class="o">-&gt;</span><span class="nb">chr</span> <span class="p">:</span>
        <span class="s">''' return chr of named special char '''</span>
        <span class="k">try</span><span class="p">:</span>
            <span class="n">c</span> <span class="o">=</span> <span class="nb">chr</span><span class="p">(</span><span class="bp">self</span><span class="p">.</span><span class="n">dic_char</span><span class="p">[</span><span class="n">name</span><span class="p">][</span><span class="mi">0</span><span class="p">])</span>
        <span class="k">except</span><span class="p">:</span>
            <span class="n">c</span> <span class="o">=</span>  <span class="nb">chr</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span>
        <span class="k">return</span> <span class="n">c</span>
    
    <span class="k">def</span> <span class="nf">scroll</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">s</span><span class="p">:</span><span class="nb">str</span><span class="p">,</span> <span class="n">lig</span><span class="p">:</span><span class="nb">int</span><span class="p">,</span> <span class="n">col</span><span class="p">:</span><span class="nb">int</span><span class="p">):</span>
        <span class="s">""" scroll string s rigth to left at (lig, col) """</span>
        <span class="n">padding</span> <span class="o">=</span> <span class="s">' '</span> <span class="o">*</span> <span class="p">(</span><span class="mi">16</span><span class="o">-</span><span class="n">col</span><span class="p">)</span>
        <span class="n">padded_s</span> <span class="o">=</span> <span class="n">padding</span> <span class="o">+</span> <span class="n">s</span>
        <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="nb">len</span><span class="p">(</span><span class="n">padded_s</span><span class="p">)):</span>
            <span class="n">lcd_text</span> <span class="o">=</span> <span class="n">padded_s</span><span class="p">[</span><span class="n">i</span><span class="p">:(</span><span class="n">i</span><span class="o">+</span><span class="mi">16</span><span class="o">-</span><span class="n">col</span><span class="p">)]</span>
            <span class="bp">self</span><span class="p">.</span><span class="n">move_to</span><span class="p">(</span><span class="n">col</span><span class="p">,</span><span class="n">lig</span><span class="p">)</span>
            <span class="bp">self</span><span class="p">.</span><span class="n">putstr</span><span class="p">(</span><span class="n">lcd_text</span><span class="p">)</span>
            <span class="n">sleep</span><span class="p">(</span><span class="mf">0.3</span><span class="p">)</span>
            <span class="bp">self</span><span class="p">.</span><span class="n">move_to</span><span class="p">(</span><span class="n">col</span><span class="p">,</span><span class="n">lig</span><span class="p">)</span>
            <span class="bp">self</span><span class="p">.</span><span class="n">putstr</span><span class="p">(</span><span class="n">padding</span><span class="p">)</span>
    
    <span class="k">def</span> <span class="nf">get_i2c</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">sda_pin</span><span class="p">:</span><span class="nb">int</span><span class="p">,</span> <span class="n">scl_pin</span><span class="p">:</span><span class="nb">int</span><span class="p">)</span> <span class="o">-&gt;</span><span class="n">SoftI2C</span> <span class="p">:</span>
        <span class="s">''' get i2c '''</span>
        <span class="n">i2c</span> <span class="o">=</span> <span class="n">SoftI2C</span><span class="p">(</span><span class="n">scl</span><span class="o">=</span><span class="n">Pin</span><span class="p">(</span><span class="n">scl_pin</span><span class="p">),</span> <span class="n">sda</span><span class="o">=</span><span class="n">Pin</span><span class="p">(</span><span class="n">sda_pin</span><span class="p">),</span> <span class="n">freq</span><span class="o">=</span><span class="mi">400000</span><span class="p">)</span>
        <span class="n">devices</span> <span class="o">=</span><span class="n">i2c</span><span class="p">.</span><span class="n">scan</span><span class="p">()</span>      
        <span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">devices</span><span class="p">)</span> <span class="o">==</span> <span class="mi">0</span><span class="p">:</span>
             <span class="k">print</span><span class="p">(</span><span class="s">"No i2c device !"</span><span class="p">)</span>
             <span class="k">return</span> <span class="bp">None</span>
        <span class="k">else</span><span class="p">:</span>
            <span class="k">print</span><span class="p">(</span><span class="s">'i2c devices found:'</span><span class="p">,</span><span class="nb">len</span><span class="p">(</span><span class="n">devices</span><span class="p">))</span>
            <span class="k">for</span> <span class="n">device</span> <span class="ow">in</span> <span class="n">devices</span><span class="p">:</span>
                <span class="k">print</span><span class="p">(</span><span class="s">"At address: "</span><span class="p">,</span><span class="nb">hex</span><span class="p">(</span><span class="n">device</span><span class="p">))</span>
            <span class="k">return</span> <span class="n">i2c</span>
        
<span class="k">if</span> <span class="n">__name__</span> <span class="o">==</span> <span class="s">'__main__'</span><span class="p">:</span>
    <span class="k">print</span><span class="p">(</span><span class="s">'test lcd'</span><span class="p">)</span>            
    <span class="n">screen</span><span class="o">=</span><span class="n">LCD</span><span class="p">()</span>
    <span class="n">screen</span><span class="p">.</span><span class="n">putstr</span><span class="p">(</span><span class="n">screen</span><span class="p">.</span><span class="n">get_char</span><span class="p">(</span><span class="s">'papsdroid'</span><span class="p">)</span> <span class="o">+</span> <span class="s">"  papsdroid  "</span> <span class="o">+</span> <span class="n">screen</span><span class="p">.</span><span class="n">get_char</span><span class="p">(</span><span class="s">'papsdroid'</span><span class="p">))</span>
    <span class="n">screen</span><span class="p">.</span><span class="n">move_to</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span><span class="mi">1</span><span class="p">)</span> <span class="c1">#second line
</span>    <span class="c1">#print symbols
</span>    <span class="n">screen</span><span class="p">.</span><span class="n">putstr</span><span class="p">(</span><span class="s">' '</span><span class="o">+</span><span class="n">screen</span><span class="p">.</span><span class="n">get_char</span><span class="p">(</span><span class="s">'wifi'</span><span class="p">))</span>
    <span class="n">screen</span><span class="p">.</span><span class="n">putstr</span><span class="p">(</span><span class="s">' '</span><span class="o">+</span><span class="n">screen</span><span class="p">.</span><span class="n">get_char</span><span class="p">(</span><span class="s">'thermometre'</span><span class="p">))</span>
    <span class="n">screen</span><span class="p">.</span><span class="n">putstr</span><span class="p">(</span><span class="s">' '</span><span class="o">+</span><span class="n">screen</span><span class="p">.</span><span class="n">get_char</span><span class="p">(</span><span class="s">'soleil'</span><span class="p">))</span>
    <span class="n">screen</span><span class="p">.</span><span class="n">putstr</span><span class="p">(</span><span class="s">' '</span><span class="o">+</span><span class="n">screen</span><span class="p">.</span><span class="n">get_char</span><span class="p">(</span><span class="s">'nuages'</span><span class="p">))</span>
    <span class="n">screen</span><span class="p">.</span><span class="n">putstr</span><span class="p">(</span><span class="s">' '</span><span class="o">+</span><span class="n">screen</span><span class="p">.</span><span class="n">get_char</span><span class="p">(</span><span class="s">'pluie'</span><span class="p">))</span>
    <span class="n">screen</span><span class="p">.</span><span class="n">putstr</span><span class="p">(</span><span class="s">' '</span><span class="o">+</span><span class="n">screen</span><span class="p">.</span><span class="n">get_char</span><span class="p">(</span><span class="s">'neige'</span><span class="p">))</span>
    <span class="n">screen</span><span class="p">.</span><span class="n">putstr</span><span class="p">(</span><span class="s">' '</span><span class="o">+</span><span class="n">screen</span><span class="p">.</span><span class="n">get_char</span><span class="p">(</span><span class="s">'brouillard'</span><span class="p">))</span>
    <span class="n">sleep</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>
    <span class="n">screen</span><span class="p">.</span><span class="n">scroll</span><span class="p">(</span><span class="s">'https://papsdroidfr.github.io/'</span><span class="p">,</span> <span class="n">lig</span><span class="o">=</span><span class="mi">0</span><span class="p">,</span> <span class="n">col</span><span class="o">=</span><span class="mi">2</span><span class="p">)</span>
    <span class="n">screen</span><span class="p">.</span><span class="n">move_to</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span><span class="mi">0</span><span class="p">)</span>
    <span class="n">screen</span><span class="p">.</span><span class="n">putstr</span><span class="p">(</span><span class="n">screen</span><span class="p">.</span><span class="n">get_char</span><span class="p">(</span><span class="s">'papsdroid'</span><span class="p">)</span> <span class="o">+</span> <span class="s">"  papsdroid  "</span> <span class="o">+</span> <span class="n">screen</span><span class="p">.</span><span class="n">get_char</span><span class="p">(</span><span class="s">'papsdroid'</span><span class="p">))</span>
</code></pre></div></div>]]></content><author><name>PapsDroid</name><email>papsdroid.fr@gmail.com</email></author><category term="DEV" /><category term="pybstick" /><category term="micro-python" /><category term="ESP32" /><category term="écran LCD" /><summary type="html"><![CDATA[ESP32 et affichage sur écran LCD I2C]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://papsdroidfr.github.io//assets/images/tutos/036ESP32meteo/lcd.jpg" /><media:content medium="image" url="https://papsdroidfr.github.io//assets/images/tutos/036ESP32meteo/lcd.jpg" xmlns:media="http://search.yahoo.com/mrss/" /></entry></feed>