Jujens' blog - Arduino - RPi - Robotique//www.jujens.eu/2015-11-08T00:00:00+01:00Se connecter en wifi à une raspberry pi2015-11-08T00:00:00+01:002015-11-08T00:00:00+01:00Julien Enselmetag:www.jujens.eu,2015-11-08:/posts/2015/Nov/08/rpi-wifi/<div class="contents topic" id="sommaire">
<p class="topic-title">Sommaire</p>
<ul class="simple">
<li><a class="reference internal" href="#connexion" id="id1">Connexion</a><ul>
<li><a class="reference internal" href="#rendre-la-configuration-permanente" id="id2">Rendre la configuration permanente</a></li>
<li><a class="reference internal" href="#configurer-son-router" id="id3">Configurer son router</a></li>
</ul>
</li>
<li><a class="reference internal" href="#en-complement" id="id4">En complément</a></li>
<li><a class="reference internal" href="#problemes-possibles" id="id5">Problèmes possibles</a></li>
</ul>
</div>
<p>Par défaut la raspi peut communiquer en Ethernet mais on peut brancher sur un de
ses ports USB un petit dongle wifi pour communiquer sans fil (cela se présente
comme une petite clé USB). J'ai pour ma …</p><div class="contents topic" id="sommaire">
<p class="topic-title">Sommaire</p>
<ul class="simple">
<li><a class="reference internal" href="#connexion" id="id1">Connexion</a><ul>
<li><a class="reference internal" href="#rendre-la-configuration-permanente" id="id2">Rendre la configuration permanente</a></li>
<li><a class="reference internal" href="#configurer-son-router" id="id3">Configurer son router</a></li>
</ul>
</li>
<li><a class="reference internal" href="#en-complement" id="id4">En complément</a></li>
<li><a class="reference internal" href="#problemes-possibles" id="id5">Problèmes possibles</a></li>
</ul>
</div>
<p>Par défaut la raspi peut communiquer en Ethernet mais on peut brancher sur un de
ses ports USB un petit dongle wifi pour communiquer sans fil (cela se présente
comme une petite clé USB). J'ai pour ma part acheté un Edimax EW-7811Un.</p>
<p>Normalement rien de très compliqué. Je détaille ici la procédure pour
Archlinux. Pour une autre distribution, les manipulations devraient être
similaires.</p>
<p>NB : il est tout à fait possible de tout configurer sans écran via SSH en étant
relié par <a class="reference external" href="//www.jujens.eu/posts/2014/Jan/12/relier-rpi-pc-ethernet/">éthernet à la raspi</a>.</p>
<div class="section" id="connexion">
<h2><a class="toc-backref" href="#id1">Connexion</a></h2>
<p>Normalement, il suffit de brancher le dongle et de démarrer la raspi. Pour
tester que tout est correct, vous pouvez utiliser la commande suivante :</p>
<pre class="literal-block">
wifi-menu -o
</pre>
<p>Vous devriez voir la liste de tous les réseaux wifi disponibles et pouvoir vous
connecter au votre.</p>
<p>Voir <a class="reference internal" href="#problemes-possibles">Problèmes possibles</a> si ça ne marche pas.</p>
<div class="section" id="rendre-la-configuration-permanente">
<h3><a class="toc-backref" href="#id2">Rendre la configuration permanente</a></h3>
<p>Nous allons utiliser <tt class="docutils literal">netctl</tt> pour nous connecter automatiquement en wifi à
notre réseau. Pour cela, nous allons utiliser un profil pré-rempli fournit avec
<tt class="docutils literal">netctl</tt>.</p>
<pre class="code bash literal-block">
<span class="nb">cd</span> /etc/netctl
cp examples/wireless-wpa .
vim wireless-wap <span class="c1"># Éditer le fichier pour renseigner le SSID et la clé
</span>netctl start wireless-wpa <span class="c1"># Démarre netctl, vous devriez pouvoir utiliser le wifi
</span>netctl <span class="nb">enable</span> wireless-wpa <span class="c1"># Active netctl au démarrage.</span>
</pre>
<p>Pour plus d'informations sur <tt class="docutils literal">netctl</tt> voir <a class="reference external" href="https://wiki.archlinux.org/index.php/Netctl">la page de wiki d'Archlinux</a>.</p>
</div>
<div class="section" id="configurer-son-router">
<h3><a class="toc-backref" href="#id3">Configurer son router</a></h3>
<p>Pour que la solution soit vraiment pratique, il reste à configurer le routeur
wifi pour qu'il donne une ip fixe à la raspi. Cela permettra de renseigner
l'adresse de la raspi dans le <tt class="docutils literal">/etc/hosts</tt> et de pouvoir l'utiliser
facilement.</p>
<p>Dans le cas de ma BBox, il faut aller sur <a class="reference external" href="http://192.168.1.254/">http://192.168.1.254/</a> puis
configuration du routeur puis DHCP. L'interface permet facilement d'associer une
ip à une adresse MAC. Si vous êtes fleimard comme moi, vous connectez la raspi
au réseau puis choisissez sa MAC dans la liste déroulante avant de la
redémarrer.</p>
<img alt="L'interface d'administration du serveur DHCP de ma BBox" src="/images/bbox-dhcp.png" style="width: 90%;" />
<p>Et voilà ! Si vous avez des questions, vous pouvez laisser un commentaire.</p>
</div>
</div>
<div class="section" id="en-complement">
<h2><a class="toc-backref" href="#id4">En complément</a></h2>
<ul class="simple">
<li><a class="reference external" href="//www.jujens.eu/posts/2014/Jan/12/relier-rpi-pc-ethernet/">Relier sa Raspberry Pi à son PC directement en Ethernet</a></li>
</ul>
</div>
<div class="section" id="problemes-possibles">
<h2><a class="toc-backref" href="#id5">Problèmes possibles</a></h2>
<p>Si la raspi ne détecte pas votre carte wifi (possible si votre noyau est un peu
ancien), il faut installer le driver à la main. Sous Archlinux, vous pouvez utiliser</p>
<pre class="literal-block">
pacman -Sy dkms-8192cu
</pre>
<p>pour l'installer. La compilation du module noyau prend un peu de temps (~12
minutes chez moi). Si la compilation rate car la fonction <tt class="docutils literal">strnicmp</tt> n'est pas
trouvé, utiliser la version <a class="reference external" href="https://github.com/Jenselme/8192cu-dkms">patchée du module</a>. Pour l'installer :</p>
<pre class="code bash literal-block">
git clone https://github.com/Jenselme/8192cu-dkms.git
<span class="nb">cd</span> 8192cu-dkms
makepkg -si
</pre>
</div>
La communication série avec arduino2014-05-05T00:00:00+02:002014-05-05T00:00:00+02:00Julien Enselmetag:www.jujens.eu,2014-05-05:/posts/2014/May/05/Communication-serie/<p>La communication série est indispensable pour dialoguer avec votre Arduino
puisque c'est le mode de transmission utilisé pour communiquer avec la
carte. Dans ce tuto je vais vous expliquer comment ça fonctionne avec des
exemples pratiques pour faire communiquer une carte arduino (le modèle n'importe
pas) et votre PC grâce …</p><p>La communication série est indispensable pour dialoguer avec votre Arduino
puisque c'est le mode de transmission utilisé pour communiquer avec la
carte. Dans ce tuto je vais vous expliquer comment ça fonctionne avec des
exemples pratiques pour faire communiquer une carte arduino (le modèle n'importe
pas) et votre PC grâce à une connexion USB. Nous utiliserons dans un premier
temps l'IDE Arduino puis du code Python. Je suppose que vous avez quelques bases
en programmation. Les exemples seront suffisamment simples pour que la
connaissance préalable de python ne soit pas nécessaire.</p>
<p>Le tuto peut se réaliser indifféremment sous Windows, GNU/Linux, Mac ou
autre. Néanmoins, les exemples fonctionnent tel quel uniquement sous linux. Sous
d'autres systèmes, vous pouvez être amené à changer les chemins des ports. Le
reste devrait rester inchangé.</p>
<p>Tous les codes sont disponibles en <a class="reference internal" href="#telechargement">téléchargement</a> à la fin de ce document sous
licence <a class="reference external" href="http://www.apache.org/licenses/LICENSE-2.0.html">Apache v2</a>.</p>
<div class="contents topic" id="sommaire">
<p class="topic-title"><strong>Sommaire</strong></p>
<ul class="simple">
<li><a class="reference internal" href="#presentation" id="id2">Présentation</a></li>
<li><a class="reference internal" href="#pre-requis" id="id3">Pré-requis</a><ul>
<li><a class="reference internal" href="#logiciels-et-bibliotheques-a-installer" id="id4">Logiciels et bibliothèques à installer</a></li>
<li><a class="reference internal" href="#vocabulaire" id="id5">Vocabulaire</a></li>
</ul>
</li>
<li><a class="reference internal" href="#communiquer-avec-le-moniteur-serie" id="id6">Communiquer avec le moniteur série</a><ul>
<li><a class="reference internal" href="#communication-la-plus-simple-possible" id="id7">Communication la plus simple possible</a></li>
<li><a class="reference internal" href="#echo" id="id8">Echo</a></li>
</ul>
</li>
<li><a class="reference internal" href="#lire-des-entiers" id="id9">Lire des entiers</a><ul>
<li><a class="reference internal" href="#lecture-basique-d-un-entier" id="id10">Lecture basique d'un entier</a></li>
<li><a class="reference internal" href="#faire-des-maths-avec-deux-entiers" id="id11">Faire des maths avec deux entiers</a></li>
</ul>
</li>
<li><a class="reference internal" href="#communication-entre-un-programme-et-la-carte" id="id12">Communication entre un programme et la carte</a><ul>
<li><a class="reference internal" href="#lecture" id="id13">Lecture</a></li>
<li><a class="reference internal" href="#ecriture" id="id14">Écriture</a></li>
</ul>
</li>
<li><a class="reference internal" href="#influence-du-nombre-de-bauds" id="id15">Influence du nombre de bauds</a></li>
<li><a class="reference internal" href="#conclusion" id="id16">Conclusion</a><ul>
<li><a class="reference internal" href="#en-resume" id="id17">En résumé</a></li>
</ul>
</li>
<li><a class="reference internal" href="#quelques-problemes-frequents" id="id18">Quelques problèmes fréquents</a><ul>
<li><a class="reference internal" href="#probleme-de-telechargement" id="id19">Problème de téléchargement</a></li>
<li><a class="reference internal" href="#lecture-de-donnees-de-taille-indeterminees" id="id20">Lecture de données de taille indéterminées</a></li>
</ul>
</li>
<li><a class="reference internal" href="#telechargements" id="id21">Téléchargements</a></li>
</ul>
</div>
<div class="section" id="presentation">
<h2><a class="toc-backref" href="#id2">Présentation</a></h2>
<p>En communication série, on découpe l'information à transmettre en petits blocs
de taille fixe avant de la transmettre. La taille des blocs correspond au nombre
des lignes disponibles pour la transmission des données.</p>
<p>Ce type de communication s'oppose à la communication parallèle. En communication
parallèle, il y a une ligne par bits à transmettre. Tous les bits sont donc
transmis en même temps. Pour une même fréquence de communication, la
communication parallèle est donc plus rapide.</p>
<p>L'avantage de la communication série sur la communication parallèle est qu'elle
nécessite moins de lignes, donc moins de broches, donc moins de composants. Son
coût est donc plus faible.</p>
<p>Les protocoles de communication série les plus connus sont :</p>
<ul class="simple">
<li>Le protocole <a class="reference external" href="http://fr.wikipedia.org/wiki/Universal_Serial_Bus">USB</a></li>
<li>Le protocole <a class="reference external" href="http://fr.wikipedia.org/wiki/I2C">I2C</a></li>
<li>Le protocole <a class="reference external" href="http://fr.wikipedia.org/wiki/PCI_Express">PCI Express</a></li>
</ul>
</div>
<div class="section" id="pre-requis">
<h2><a class="toc-backref" href="#id3">Pré-requis</a></h2>
<div class="section" id="logiciels-et-bibliotheques-a-installer">
<h3><a class="toc-backref" href="#id4">Logiciels et bibliothèques à installer</a></h3>
<ul class="simple">
<li>Arduino IDE : l'IDE officiel arduino. Le moyen le plus simple d'écrire et de
télécharger les programmes sur la carte. Il est disponible sur le site
officiel d'Arduino : <a class="reference external" href="http://arduino.cc/en/Main/Software#toc1">http://arduino.cc/en/Main/Software#toc1</a></li>
<li>Python3 : indispensable pour exécuter les certains programmes d'exemple
(uniquement pour la partie <a class="reference internal" href="#communication-entre-un-programme-et-la-carte">communication entre un programme et la
carte</a>). Il se trouve dans les dépôts de votre distribution linux ou par là :
<a class="reference external" href="http://www.python.org/">Python</a></li>
<li>Pyserial : c'est la bibliothèque python qui permet de faire de la
communication série. Elle est normalement dans les dépôts de votre
distribution linux. Elle peut aussi être installée via <a class="reference external" href="https://pypi.python.org/pypi/pyserial/2.7">pip</a> : <tt class="docutils literal">pip install pyserial</tt>.</li>
</ul>
</div>
<div class="section" id="vocabulaire">
<h3><a class="toc-backref" href="#id5">Vocabulaire</a></h3>
<p>Commençons par définir quelques termes de vocabulaire avec lesquels vous pouvez
ne pas être familier et que nous allons rencontrer tout au long de ce tuto :</p>
<ul class="simple">
<li>Ascii : c'est l'acronyme de <em>American Standard Code for Information
Exchange</em>, soit code américain pour l'échange d'information. Ce code permet de
représenter avec des nombres compris entre 0 et 127 les caractères utilisés
dans l'alphabet américain soit :<ul>
<li>Les lettres, minuscules et majuscules</li>
<li>Les symboles de ponctuation : <tt class="docutils literal">. , ;</tt></li>
<li>Des caractères spéciaux : <tt class="docutils literal">$ # * +</tt></li>
<li>Pas les accents</li>
</ul>
</li>
<li>Baud (Bd) : Unité de mesure du nombre de symboles transmissibles par
seconde. Il ne faut pas le confondre avec le nombre de bits par seconde
(bps). Par exemple, considérons que l'on souhaite transmettre le symbole ascii
<tt class="docutils literal">a</tt> en 1 seconde exactement. D'après la <a class="reference external" href="http://fr.wikipedia.org/wiki/American_Standard_Code_for_Information_Interchange#Table_des_128_caract.C3.A8res_ASCII">table ascii</a>
<tt class="docutils literal">a</tt> s'écrit en binaire <tt class="docutils literal">01100001</tt>. Pour transmettre ce symbole en 1
seconde, il faut communiquer avec une vitesse de 1 Bd mais de 8 bps.</li>
<li>Bytes (en python3) : Petite précision de vocabulaire spécifique à
python 3. C'est un type de base du langage qui représente une chaîne
d'octets. C'est ce type de donnée que nous manipulerons dans <a class="reference internal" href="#communication-entre-un-programme-et-la-carte">communication
entre un programme et la carte</a></li>
</ul>
</div>
</div>
<div class="section" id="communiquer-avec-le-moniteur-serie">
<h2><a class="toc-backref" href="#id6">Communiquer avec le moniteur série</a></h2>
<p>Avant de rentrer vraiment dans la communication, je vous signale que deux
diodes présentes sur la arduino, peuvent être utiles :</p>
<ul class="simple">
<li>TX : s'allume lors d'une transmission</li>
<li>RX : s'allume lors d'une réception</li>
</ul>
<img alt="Une arduino et ses diodes TX et RX" class="center" src="/static/communication-serie/arduino-uno-TX-RX.jpg" style="width: 427.5px; height: 296.5px;" />
<div class="section" id="communication-la-plus-simple-possible">
<h3><a class="toc-backref" href="#id7">Communication la plus simple possible</a></h3>
<p>Nous allons aborder notre premier exemple. Il consiste à envoyer des données sur
le port série de la arduino de d'utiliser l'outil intégré à l'IDE pour voir les
données envoyées. Lancez l'éditeur arduino et entrez le code ci-dessous :</p>
<pre class="code c++ literal-block">
<span class="kt">void</span> <span class="nf">setup</span><span class="p">()</span> <span class="p">{</span>
<span class="n">Serial</span><span class="p">.</span><span class="n">begin</span><span class="p">(</span><span class="mi">9600</span><span class="p">);</span>
<span class="p">}</span>
<span class="kt">void</span> <span class="nf">loop</span><span class="p">()</span> <span class="p">{</span>
<span class="n">Serial</span><span class="p">.</span><span class="n">println</span><span class="p">(</span><span class="s">"Coucou"</span><span class="p">);</span>
<span class="p">}</span>
</pre>
<p>Détaillons le :</p>
<ul class="simple">
<li>Dans la fonction <tt class="docutils literal">setup</tt>, on initialise simplement le port série
en donnant sa vitesse avec <tt class="docutils literal">Serial.begin(9600)</tt>. En effet, pour que la carte
et l'ordinateur communique correctement, ils doivent « parler » à la même
vitesse. Une vitesse différente est une erreur fréquente au début. Pensez à la
vérifier si vous rencontrez des problèmes. On choisit ici 9600 Bd ce qui est une
valeur classique. Nous verrons plus loin l'<a class="reference internal" href="#influence-du-nombre-de-bauds">influence du nombre de bauds</a>.</li>
<li>Dans la fonction <tt class="docutils literal">loop</tt>, on se contente d'envoyer <tt class="docutils literal">"Coucou"</tt> avec
<tt class="docutils literal"><span class="pre">Serial.println("Coucou")</span></tt>.</li>
</ul>
<p>Vérifiez dans <em>Outils > Carte</em> que la bonne carte est sélectionnée et dans
<em>Outils > Port série</em> que le bon port est choisi. Si tout est bon, utilisez le
bouton <em>Téléchargements</em> pour envoyer le code sur la carte.</p>
<p>Ouvrez le moniteur série avec <em>Outils > Moniteur série</em>. Vérifiez en bas à
droite que la valeur est bien à 9600 Bd. Si tout va bien, vous devriez voir le
moniteur se remplir de <tt class="docutils literal">Coucou</tt>.</p>
<img alt="Le moniteur série" class="center" src="/static/communication-serie/moniteur-serie.png" />
<p>Si ce n'est pas le cas, reprenez les étapes précédentes, vous avez raté quelque
chose. Vous pouvez aussi regarder du côté des <a class="reference internal" href="#quelques-problemes-frequents">quelques problèmes fréquents</a>.</p>
</div>
<div class="section" id="echo">
<h3><a class="toc-backref" href="#id8">Echo</a></h3>
<p>Après cet exemple d'autant moins intéressant qu'il ne fonctionne que dans un
sens, faisons un programme d'écho : la arduino va nous renvoyer exactement ce
qu'on lui envoie. Si elle ne reçoit rien, elle envoie <tt class="docutils literal">Rien</tt>. Voilà le code de
la arduino :</p>
<pre class="code c++ literal-block">
<span class="kt">void</span> <span class="nf">setup</span><span class="p">()</span> <span class="p">{</span>
<span class="n">Serial</span><span class="p">.</span><span class="n">begin</span><span class="p">(</span><span class="mi">9600</span><span class="p">);</span>
<span class="p">}</span>
<span class="kt">void</span> <span class="nf">loop</span><span class="p">()</span> <span class="p">{</span>
<span class="k">if</span> <span class="p">(</span> <span class="n">Serial</span><span class="p">.</span><span class="n">available</span><span class="p">()</span> <span class="p">)</span> <span class="p">{</span>
<span class="kt">int</span> <span class="n">lu</span> <span class="o">=</span> <span class="n">Serial</span><span class="p">.</span><span class="n">read</span><span class="p">();</span>
<span class="n">Serial</span><span class="p">.</span><span class="n">println</span><span class="p">(</span><span class="n">lu</span><span class="p">);</span>
<span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
<span class="n">Serial</span><span class="p">.</span><span class="n">println</span><span class="p">(</span><span class="s">"Rien"</span><span class="p">);</span>
<span class="p">}</span>
<span class="n">delay</span><span class="p">(</span><span class="mi">2000</span><span class="p">);</span>
<span class="p">}</span>
</pre>
<p>Regardons le d'un peu plus près. Pas de changement du côté de <tt class="docutils literal">setup</tt>. Dans
<tt class="docutils literal">loop</tt> :</p>
<ul class="simple">
<li>Nous commençons par vérifier si des données en attente de lecture sur le port
avec : <tt class="docutils literal">Serial.available()</tt>. Cette fonction renvoie <tt class="docutils literal">true</tt> si telle est le
cas.</li>
<li>Si on a des données, on définit une variable de type <tt class="docutils literal">int</tt> dans laquelle on
place une donnée en attente. Puis on affiche cette donnée.</li>
<li>Sinon, on affiche <tt class="docutils literal">Rien</tt>.</li>
<li>Enfin, on attend 2 secondes histoire d'avoir le temps de voir ce qui se passe.</li>
</ul>
<p>Testez ce code. Pour envoyer une donnée à la carte, tapez du texte dans la barre
du haut puis presser <em>Entrée</em> ou appuyez sur <em>Envoyer</em>. Vous devriez obtenir
quelque chose comme ça (j'ai tapé <em>coucou</em>) :</p>
<img alt="La réponse "écho" de la carte à "coucou"" class="center" src="/static/communication-serie/echo.png" />
<p><em>Mais ce n'est pas ce que j'ai tapé !</em> En effet, <tt class="docutils literal">Serial.read()</tt> lit un octet
de données sur le port série. Ni plus, ni moins. Et c'est la <a class="reference external" href="http://arduino.cc/en/Serial/Read">seule manière</a> de lire les données. Mais rassurez-vous,
vous pouvez facilement donner un sens à ce qui s'affiche : les données sont
encodées en ascii. Par conséquent, le numéro qui s'affiche est la version
décimale du code ascii. Vous pouvez consulter la <a class="reference external" href="http://fr.wikipedia.org/wiki/American_Standard_Code_for_Information_Interchange#Table_des_128_caract.C3.A8res_ASCII">table</a>
pour convertir ce code dans le caractère standard.</p>
</div>
</div>
<div class="section" id="lire-des-entiers">
<h2><a class="toc-backref" href="#id9">Lire des entiers</a></h2>
<p>Dans cette partie, nous allons utiliser la table ascii pour convertir le nombre
reçu en quelque chose d'exploitable. Nous ferons tout d'abord un programme qui
lit et affiche correctement un nombre puis un second programme qui fera des
opérations sur deux entiers que vous choisirez.</p>
<div class="section" id="lecture-basique-d-un-entier">
<h3><a class="toc-backref" href="#id10">Lecture basique d'un entier</a></h3>
<p>Ce n'est pas très compliqué. Il suffit de prendre la table ascii et de constater
que les chiffres sont codés en décimal entre 48 et 57 puis de décaler.</p>
<pre class="code c++ literal-block">
<span class="kt">int</span> <span class="n">byte_read</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="c1">///< The current byte
</span><span class="kt">int</span> <span class="n">recieved_integer</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="c1">///< The current recieved integer
</span>
<span class="kt">void</span> <span class="nf">setup</span><span class="p">()</span> <span class="p">{</span>
<span class="n">Serial</span><span class="p">.</span><span class="n">begin</span><span class="p">(</span><span class="mi">9600</span><span class="p">);</span>
<span class="p">}</span>
<span class="n">boolean</span> <span class="nf">is_a_number</span><span class="p">(</span><span class="kt">int</span> <span class="n">n</span><span class="p">)</span>
<span class="p">{</span>
<span class="k">return</span> <span class="n">n</span> <span class="o">>=</span> <span class="mi">48</span> <span class="o">&&</span> <span class="n">n</span> <span class="o"><=</span> <span class="mi">57</span><span class="p">;</span>
<span class="p">}</span>
<span class="kt">int</span> <span class="nf">ascii2int</span><span class="p">(</span><span class="kt">int</span> <span class="n">n</span><span class="p">,</span> <span class="kt">int</span> <span class="n">byte_read</span><span class="p">)</span>
<span class="p">{</span>
<span class="k">return</span> <span class="n">n</span><span class="o">*</span><span class="mi">10</span> <span class="o">+</span> <span class="p">(</span><span class="n">byte_read</span> <span class="o">-</span> <span class="mi">48</span><span class="p">);</span>
<span class="p">}</span>
<span class="kt">void</span> <span class="nf">loop</span><span class="p">()</span> <span class="p">{</span>
<span class="n">recieved_integer</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
<span class="k">while</span> <span class="p">(</span> <span class="n">Serial</span><span class="p">.</span><span class="n">available</span><span class="p">()</span> <span class="p">)</span> <span class="p">{</span>
<span class="n">byte_read</span> <span class="o">=</span> <span class="n">Serial</span><span class="p">.</span><span class="n">read</span><span class="p">();</span>
<span class="k">if</span> <span class="p">(</span> <span class="n">is_a_number</span><span class="p">(</span><span class="n">byte_read</span><span class="p">)</span> <span class="p">)</span> <span class="p">{</span>
<span class="n">recieved_integer</span> <span class="o">=</span> <span class="n">ascii2int</span><span class="p">(</span><span class="n">recieved_integer</span><span class="p">,</span> <span class="n">byte_read</span><span class="p">);</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="n">Serial</span><span class="p">.</span><span class="n">println</span><span class="p">(</span> <span class="n">recieved_integer</span> <span class="p">);</span>
<span class="n">delay</span><span class="p">(</span><span class="mi">1000</span><span class="p">);</span>
<span class="p">}</span>
</pre>
<p>Détaillons ce programme :</p>
<ul class="simple">
<li>On définit les variables globales en début de programme. Ça ne sert à rien de
les redéfinir à chaque tour de boucle.</li>
<li>Ensuite on définit deux fonctions :<ul>
<li><tt class="docutils literal">boolean is_a_number(int n)</tt> qui renvoie vrai si on lui donne un nombre
ascii codé en décimal.</li>
<li><tt class="docutils literal">int ascii2int(int n, int byte_read)</tt> qui renvoie le nombre sous la forme
d'un entier. Elle prend en paramètre l'entier déjà calculé ainsi que l'octet
à ajouter.</li>
</ul>
</li>
<li>Dans <tt class="docutils literal">loop</tt> : on fait la conversion si un entier est disponible.</li>
</ul>
<p>Je vous laisse constater que ça marche bien.</p>
</div>
<div class="section" id="faire-des-maths-avec-deux-entiers">
<h3><a class="toc-backref" href="#id11">Faire des maths avec deux entiers</a></h3>
<p>Maintenant on va faire un peu mieux : lire deux entiers séparés par une virgule
et les additionner. Le code est ci-dessous :</p>
<pre class="code c++ literal-block">
<span class="k">const</span> <span class="kt">int</span> <span class="n">baudrate</span> <span class="o">=</span> <span class="mi">9600</span><span class="p">;</span>
<span class="kt">int</span> <span class="n">byte_read</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="c1">///< The current byte read.
</span><span class="kt">int</span> <span class="n">coords</span><span class="p">[</span><span class="mi">2</span><span class="p">];</span> <span class="c1">///< Contains x and y.
</span><span class="kt">int</span> <span class="n">index</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="c1">///< 0: reading x, 1: reading y.
</span><span class="kt">int</span> <span class="n">separator</span> <span class="o">=</span> <span class="mi">44</span><span class="p">;</span> <span class="c1">///< The separator between the integers (44: ,)
</span>
<span class="kt">void</span> <span class="nf">setup</span><span class="p">()</span>
<span class="p">{</span>
<span class="n">Serial</span><span class="p">.</span><span class="n">begin</span><span class="p">(</span><span class="n">baudrate</span><span class="p">);</span>
<span class="p">}</span>
<span class="n">boolean</span> <span class="nf">is_a_number</span><span class="p">(</span><span class="kt">int</span> <span class="n">n</span><span class="p">)</span>
<span class="p">{</span>
<span class="k">return</span> <span class="n">n</span> <span class="o">>=</span> <span class="mi">48</span> <span class="o">&&</span> <span class="n">n</span> <span class="o"><=</span> <span class="mi">57</span><span class="p">;</span>
<span class="p">}</span>
<span class="kt">int</span> <span class="nf">ascii2int</span><span class="p">(</span><span class="kt">int</span> <span class="n">n</span><span class="p">,</span> <span class="kt">int</span> <span class="n">byte_read</span><span class="p">)</span>
<span class="p">{</span>
<span class="k">return</span> <span class="n">n</span><span class="o">*</span><span class="mi">10</span> <span class="o">+</span> <span class="p">(</span><span class="n">byte_read</span> <span class="o">-</span> <span class="mi">48</span><span class="p">);</span>
<span class="p">}</span>
<span class="kt">void</span> <span class="nf">loop</span><span class="p">()</span>
<span class="p">{</span>
<span class="n">coords</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
<span class="n">coords</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
<span class="n">index</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
<span class="k">while</span> <span class="p">(</span> <span class="n">Serial</span><span class="p">.</span><span class="n">available</span><span class="p">()</span> <span class="o">></span> <span class="mi">0</span> <span class="p">)</span>
<span class="p">{</span>
<span class="n">byte_read</span> <span class="o">=</span> <span class="n">Serial</span><span class="p">.</span><span class="n">read</span><span class="p">();</span>
<span class="k">if</span> <span class="p">(</span> <span class="n">is_a_number</span><span class="p">(</span><span class="n">byte_read</span><span class="p">)</span> <span class="p">)</span>
<span class="p">{</span>
<span class="n">coords</span><span class="p">[</span><span class="n">index</span><span class="p">]</span> <span class="o">=</span> <span class="n">ascii2int</span><span class="p">(</span> <span class="n">coords</span><span class="p">[</span><span class="n">index</span><span class="p">],</span> <span class="n">byte_read</span> <span class="p">);</span>
<span class="p">}</span>
<span class="k">else</span> <span class="k">if</span> <span class="p">(</span> <span class="n">byte_read</span> <span class="o">==</span> <span class="n">separator</span> <span class="p">)</span>
<span class="p">{</span>
<span class="o">++</span><span class="n">index</span><span class="p">;</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="k">if</span> <span class="p">(</span> <span class="n">index</span> <span class="p">)</span>
<span class="p">{</span>
<span class="n">Serial</span><span class="p">.</span><span class="n">print</span><span class="p">(</span><span class="s">"x + y = "</span><span class="p">);</span>
<span class="n">Serial</span><span class="p">.</span><span class="n">println</span><span class="p">(</span><span class="n">coords</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">+</span> <span class="n">coords</span><span class="p">[</span><span class="mi">1</span><span class="p">]);</span>
<span class="n">Serial</span><span class="p">.</span><span class="n">print</span><span class="p">(</span><span class="s">"x * y = "</span><span class="p">);</span>
<span class="n">Serial</span><span class="p">.</span><span class="n">println</span><span class="p">(</span><span class="n">coords</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">*</span> <span class="n">coords</span><span class="p">[</span><span class="mi">1</span><span class="p">]);</span>
<span class="p">}</span>
<span class="k">else</span>
<span class="p">{</span>
<span class="n">Serial</span><span class="p">.</span><span class="n">println</span><span class="p">();</span>
<span class="p">}</span>
<span class="n">delay</span><span class="p">(</span><span class="mi">1000</span><span class="p">);</span>
<span class="p">}</span>
</pre>
<p>Décortiquons :</p>
<ul class="simple">
<li>Concernant les variables :<ul>
<li>Nos deux nombres seront stockés dans un tableau d'entier.</li>
<li><tt class="docutils literal">index</tt> nous permet de savoir si on lit x ou y.</li>
</ul>
</li>
<li>Dans <tt class="docutils literal">loop</tt> :<ul>
<li>On prend soin de remettre à 0 les variables pour éviter les problèmes.</li>
<li>Puis suivant si l'octet lut représente un nombre ou le séparateur, on lit un
nombre ou on incrémente l'index.</li>
<li>Concernant les calculs : on vérifie que <tt class="docutils literal">index</tt> n'est pas à 0 et donc
qu'on a bien lut deux nombres. Si tel est le cas, on fait l'addition et la
multiplication de x et y et on affiche le résultat. La fonction <tt class="docutils literal">print</tt>
affiche ses paramètres sans revenir à la ligne comme <tt class="docutils literal">println</tt>.</li>
</ul>
</li>
</ul>
<p>Vous pouvez vous amuser à écrire une calculatrice plus complète si vous
voulez. Vous pouvez même envoyer l'opération à effectuer si vous
voulez. Utilisez éventuellement l'instruction <a class="reference external" href="http://arduino.cc/en/Reference/SwitchCase">switch</a>.</p>
</div>
</div>
<div class="section" id="communication-entre-un-programme-et-la-carte">
<h2><a class="toc-backref" href="#id12">Communication entre un programme et la carte</a></h2>
<p>Cette partie reprend en partie ce qui a déjà été évoqué <a class="reference external" href="//www.jujens.eu/posts/2014/Jan/11/communication-serie-facile-python/">ici</a> mais de façon
plus détaillée et un peu moins complète.</p>
<div class="section" id="lecture">
<h3><a class="toc-backref" href="#id13">Lecture</a></h3>
<p>Nous allons maintenant faire communiquer un programme de votre ordinateur (autre
que l'IDE Arduino) et la carte. Le code sera écrit directement dans
l'interpréteur, mais vous pouvez sans problème le mettre dans un fichier puis
l'exécuter. Il sera écrit en python, mais les principes restent les mêmes dans
les autres langages. Reprenons le code « echo » pour la carte :</p>
<pre class="code c++ literal-block">
<span class="kt">void</span> <span class="nf">setup</span><span class="p">()</span> <span class="p">{</span>
<span class="n">Serial</span><span class="p">.</span><span class="n">begin</span><span class="p">(</span><span class="mi">9600</span><span class="p">);</span>
<span class="p">}</span>
<span class="kt">void</span> <span class="nf">loop</span><span class="p">()</span> <span class="p">{</span>
<span class="k">if</span> <span class="p">(</span> <span class="n">Serial</span><span class="p">.</span><span class="n">available</span><span class="p">()</span> <span class="p">)</span> <span class="p">{</span>
<span class="kt">int</span> <span class="n">lu</span> <span class="o">=</span> <span class="n">Serial</span><span class="p">.</span><span class="n">read</span><span class="p">();</span>
<span class="n">Serial</span><span class="p">.</span><span class="n">println</span><span class="p">(</span><span class="n">lu</span><span class="p">);</span>
<span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
<span class="n">Serial</span><span class="p">.</span><span class="n">println</span><span class="p">(</span><span class="s">"Rien"</span><span class="p">);</span>
<span class="p">}</span>
<span class="n">delay</span><span class="p">(</span><span class="mi">2000</span><span class="p">);</span>
<span class="p">}</span>
</pre>
<p>Lancez l'interpréteur python sur votre PC et importer la bibliothèque pyserial :</p>
<pre class="code pycon literal-block">
<span class="go">Python 3.3.2 (default, Mar 5 2014, 08:21:05)
[GCC 4.8.2 20131212 (Red Hat 4.8.2-7)] on linux
Type "help", "copyright", "credits" or "license" for more information.
</span><span class="kn"></span><span class="gp">>>> </span><span class="kn">from</span> <span class="nn">serial</span> <span class="kn">import</span> <span class="n">Serial</span>
</pre>
<p>Créez la communication série avec (en remplaçant <tt class="docutils literal">/dev/ttyACM0</tt> par le nom de
votre port) :</p>
<pre class="code pycon literal-block">
<span class="n"></span><span class="gp">>>> </span><span class="n">serial_port</span> <span class="o">=</span> <span class="n">Serial</span><span class="p">(</span><span class="n">port</span><span class="o">=</span><span class="s1">'/dev/ttyACM0'</span><span class="p">,</span> <span class="n">baudrate</span><span class="o">=</span><span class="mi">9600</span><span class="p">)</span>
</pre>
<p>Pour lire des données, rien de plus simple :</p>
<pre class="code pycon literal-block">
<span class="n"></span><span class="gp">>>> </span><span class="n">serial_port</span><span class="o">.</span><span class="n">read</span><span class="p">()</span>
<span class="go">b'R'
</span><span class="n"></span><span class="gp">>>> </span><span class="n">serial_port</span><span class="o">.</span><span class="n">readline</span><span class="p">()</span>
<span class="go">b'Rien\r\n'</span>
</pre>
<p>Les résultats sont de type <tt class="docutils literal">bytes</tt>. Si vous comptez faire des manipulations
par la suite (hors transmission série), je vous conseille de passer dans le type
string plus adapté (ou un autre type qui représente correctement vos données) :</p>
<pre class="code pycon literal-block">
<span class="n"></span><span class="gp">>>> </span><span class="n">lu</span> <span class="o">=</span> <span class="n">serial_port</span><span class="o">.</span><span class="n">readline</span><span class="p">()</span>
<span class="gp">>>> </span><span class="n">lu</span>
<span class="go">b'Rien\r\n'
</span><span class="nb"></span><span class="gp">>>> </span><span class="nb">type</span><span class="p">(</span><span class="n">lu</span><span class="p">)</span>
<span class="go"><class 'bytes'>
</span><span class="n"></span><span class="gp">>>> </span><span class="n">chaine</span> <span class="o">=</span> <span class="n">lu</span><span class="o">.</span><span class="n">decode</span><span class="p">(</span><span class="s1">'ascii'</span><span class="p">)</span>
<span class="gp">>>> </span><span class="n">chaine</span>
<span class="go">'Rien\r\n'
</span><span class="nb"></span><span class="gp">>>> </span><span class="nb">type</span><span class="p">(</span><span class="n">chaine</span><span class="p">)</span>
<span class="go"><class 'str'></span>
</pre>
</div>
<div class="section" id="ecriture">
<h3><a class="toc-backref" href="#id14">Écriture</a></h3>
<p>Pour écrire des données c'est aussi très simple :</p>
<pre class="code pycon literal-block">
<span class="k"></span><span class="gp">>>> </span><span class="k">while</span> <span class="kc">True</span><span class="p">:</span>
<span class="gp">... </span> <span class="n">nombre</span> <span class="o">=</span> <span class="nb">input</span><span class="p">(</span><span class="s1">'Entrez un chiffre : '</span><span class="p">)</span>
<span class="gp">... </span> <span class="n">serial_port</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="n">nombre</span><span class="o">.</span><span class="n">encode</span><span class="p">(</span><span class="s1">'ascii'</span><span class="p">))</span>
<span class="gp">... </span> <span class="n">serial_port</span><span class="o">.</span><span class="n">readline</span><span class="p">()</span>
<span class="gp">...</span>
<span class="go">Entrez un nombre : 78
1
b'55\r\n'</span>
</pre>
<p>Le nombre <tt class="docutils literal">1</tt> est la valeur de retour de <tt class="docutils literal">serial_port.write</tt> qui renvoie la
longueur de la chaîne écrite.</p>
</div>
</div>
<div class="section" id="influence-du-nombre-de-bauds">
<h2><a class="toc-backref" href="#id15">Influence du nombre de bauds</a></h2>
<p>Comme vous avez dû le comprendre en lisant <a class="reference internal" href="#vocabulaire">vocabulaire</a>, plus le nombre de
bauds est élevé, plus on peut transmettre de données dans un temps court. Nous
allons illustrer ceci dans cette partie. Télécharger tout d'abord le fichier
<a class="reference external" href="//www.jujens.eu/static/communication-serie/donnees.txt">donnee.txt</a> qui contient
le texte à envoyer. Enregistrez de façon à pouvoir l'ouvrir facilement avec
l'interpréteur python. Programmez votre arduino avec le code suivant :</p>
<pre class="code c++ literal-block">
<span class="kt">void</span> <span class="nf">setup</span><span class="p">()</span> <span class="p">{</span>
<span class="n">Serial</span><span class="p">.</span><span class="n">begin</span><span class="p">(</span><span class="mi">117500</span><span class="p">);</span>
<span class="p">}</span>
<span class="kt">void</span> <span class="nf">loop</span><span class="p">()</span> <span class="p">{</span>
<span class="k">while</span> <span class="p">(</span> <span class="n">Serial</span><span class="p">.</span><span class="n">available</span><span class="p">()</span> <span class="p">)</span> <span class="p">{</span>
<span class="n">Serial</span><span class="p">.</span><span class="n">read</span><span class="p">();</span>
<span class="p">}</span>
<span class="p">}</span>
</pre>
<p>Puis dans l'interpréteur python, tapez :</p>
<pre class="code pycon literal-block">
<span class="n"></span><span class="gp">>>> </span><span class="n">port</span> <span class="o">=</span> <span class="n">Serial</span><span class="p">(</span><span class="n">port</span><span class="o">=</span><span class="s1">'/dev/ttyACM0'</span><span class="p">,</span> <span class="n">baudrate</span><span class="o">=</span><span class="mi">117500</span><span class="p">)</span>
<span class="gp">>>> </span><span class="n">f</span> <span class="o">=</span> <span class="nb">open</span><span class="p">(</span><span class="s1">'donnees.txt'</span><span class="p">,</span> <span class="s1">'r'</span><span class="p">)</span>
<span class="gp">>>> </span><span class="n">data</span> <span class="o">=</span> <span class="n">f</span><span class="o">.</span><span class="n">read</span><span class="p">()</span>
<span class="gp">>>> </span><span class="n">a</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="n">data</span><span class="o">.</span><span class="n">encode</span><span class="p">(</span><span class="s1">'ascii'</span><span class="p">))</span>
</pre>
<p>L'interpréteur devrait répondre rapidement <tt class="docutils literal">8000</tt>. Remplacez maintenant
<tt class="docutils literal">117500</tt> par <tt class="docutils literal">4800</tt> dans les deux codes. C'est <strong>beaucoup</strong> plus long, non ?</p>
<p>Le principal est d'utiliser la bonne vitesse de transmission pour son
application. Avec une grande vitesse, vous transmettez plus d'informations mais
cela peut poser des problèmes sur les grandes distances. À vous de tester et de
choisir la bonne, sachant qu'en général sur des cas simples, 9600 Bd est
suffisant.</p>
</div>
<div class="section" id="conclusion">
<h2><a class="toc-backref" href="#id16">Conclusion</a></h2>
<p>À partir de ces informations, vous devriez pouvoir faire ce que vous voulez tant
que ce n'est pas trop compliqué. Je publierais sûrement d'ici quelques temps un
tuto plus complet sur pyserial. En attendant, vous pouvez aller consulter la
<a class="reference external" href="http://pyserial.sourceforge.net/">documentation</a>.</p>
<div class="section" id="en-resume">
<h3><a class="toc-backref" href="#id17">En résumé</a></h3>
<ul class="simple">
<li>Choisir la bonne vitesse de communication.</li>
<li>Que les deux programmes qui communiquent le fasse à la même vitesse.</li>
<li>Se souvenir que l'arduino lit les données en code ascii.</li>
<li>Ne pas désespérer si ça ne fonctionne pas.</li>
</ul>
</div>
</div>
<div class="section" id="quelques-problemes-frequents">
<h2><a class="toc-backref" href="#id18">Quelques problèmes fréquents</a></h2>
<div class="section" id="probleme-de-telechargement">
<h3><a class="toc-backref" href="#id19">Problème de téléchargement</a></h3>
<p>Ils sont malheureusement courants et je n'ai pas de méthode miracle pour les
régler. Vous pouvez :</p>
<ul class="simple">
<li>Vérifiez le port de communication</li>
<li>Débranchez/Re-branchez la carte</li>
<li>Relancez l'éditeur</li>
</ul>
</div>
<div class="section" id="lecture-de-donnees-de-taille-indeterminees">
<h3><a class="toc-backref" href="#id20">Lecture de données de taille indéterminées</a></h3>
<p>Lors de tous nos tests de lecture, nous avons utilisé soit des int soit des
tableaux de taille fixe de int. Vous ne pouvez pas lire des données de taille
indéterminée avec la arduino. Par exemple, faire :</p>
<pre class="code cpp literal-block">
<span class="n">String</span> <span class="n">data</span> <span class="o">=</span> <span class="n">Serial</span><span class="p">.</span><span class="n">read</span><span class="p">();</span>
</pre>
<p>En effet, contrairement à votre ordinateur qui a <em>beaucoup</em> de mémoire, une
arduino est beaucoup plus limitée : pas plus de quelques kilos octets. La
lecture de données sous cette forme empêche le compilateur de connaître la
taille nécessaire pour la donnée et va donc refuser de compiler le code.</p>
<p>Dans tous les cas, souvenez-vous que la mémoire est <em>très</em> limitée et que vous
ne pourrez donc pas tout traiter.</p>
</div>
</div>
<div class="section" id="telechargements">
<h2><a class="toc-backref" href="#id21">Téléchargements</a></h2>
<p>Tout est sous licence <a class="reference external" href="http://www.apache.org/licenses/LICENSE-2.0.html">Apache v2</a>.</p>
<ul class="simple" id="telechargement">
<li><a class="reference external" href="//www.jujens.eu/static/communication-serie/serial_port_com/serial_port_com.ino">serial_port_com.ino</a></li>
<li><a class="reference external" href="//www.jujens.eu/static/communication-serie/lire_entier/lire_entier.ino">lire_entier.ino</a></li>
<li><a class="reference external" href="//www.jujens.eu/static/communication-serie/echo/echo.ino">echo.ino</a></li>
<li><a class="reference external" href="//www.jujens.eu/static/communication-serie/maths/maths.ino">maths.ino</a></li>
<li><a class="reference external" href="//www.jujens.eu/static/communication-serie/baud/baud.ino">baud.ino</a></li>
</ul>
<p>L'archive avec tous les codes : <a class="reference external" href="//www.jujens.eu/static/communication-serie/codes.zip">codes.zip</a></p>
</div>
Émuler une Raspberry Pi sous Linux avec Qemu2014-04-06T00:00:00+02:002014-04-06T00:00:00+02:00Julien Enselmetag:www.jujens.eu,2014-04-06:/posts/2014/Apr/06/emuler-rpi-linux-qemu/<p>Qemu est un logiciel de virtualisation qui présente l'avantage de
pouvoir émuler de façon logicielle une architecture donnée. Il vous
permet donc de simuler une architecture que vous n'avez pas, par exemple
l'architecture arm sur x86. Qemu existe aussi sous windows, mais seule
la méthode sous linux sera évoquée ici …</p><p>Qemu est un logiciel de virtualisation qui présente l'avantage de
pouvoir émuler de façon logicielle une architecture donnée. Il vous
permet donc de simuler une architecture que vous n'avez pas, par exemple
l'architecture arm sur x86. Qemu existe aussi sous windows, mais seule
la méthode sous linux sera évoquée ici. Vous pouvez vous référer à <a class="reference external" href="http://www.linux-mitterteich.de/fileadmin/datafile/papers/2013/qemu_raspiemu_lug_18_sep_2013.pdf">ce
document</a>
pour la version windows. Je signale au passage que virt-manager ne
supporte pas a priori l'architecture arm1176. Voir par
<a class="reference external" href="https://www.redhat.com/archives/virt-tools-list/2013-February/msg00115.html">là</a>
pour plus d'infos.</p>
<div class="section" id="installer-qemu">
<h2>Installer Qemu</h2>
<p>Tout d'abord, il faut installer qemu. Normalement, c'est présent dans
les dépôts de votre distribution. Sous Fedora, j'ai installé les paquets
suivants : qemu-system-arm et qemu-user. Vous devez avoir les commades
qemu-arm et qemu-system-arm une fois installé. Vérifiez que
l'achitecture arm1176 est bien supportée avec :</p>
<pre class="literal-block">
qemu-arm -cpu ? | grep arm
</pre>
<p>Vous devriez voir l'architecture correctement listée.</p>
</div>
<div class="section" id="recuperer-une-distribution-et-un-noyau">
<h2>Récupérer une distribution et un noyau</h2>
<p>Récupérez une image de la distribution de votre choix sur le site qui va
bien : <a class="reference external" href="http://www.raspberrypi.org/downloads">http://www.raspberrypi.org/downloads</a></p>
<p>Pour booter, vous allez aussi avoir besoin d'un noyau. Récuprérez le
avec :</p>
<pre class="literal-block">
wget http://xecdesign.com/downloads/linux-qemu/kernel-qemu
</pre>
</div>
<div class="section" id="augmenter-la-taille-de-l-image">
<h2>Augmenter la taille de l'image</h2>
<p>Par défaut, les images des distributions sont très petites. Vous pourrez
faire quelques tests mais pas l'utiliser comme un vrai système émulé.
Pour cela, il faut augmenter la taille de l'image avec :</p>
<pre class="literal-block">
qemu-img resize 2014-01-07-wheezy-raspbian.img +6G
</pre>
</div>
<div class="section" id="demarrer-avec-un-shell-root-pour-regler-des-details">
<h2>Démarrer avec un shell root (pour régler des détails)</h2>
<p>Lancez la commande ci-dessous pour démarrer. Vous aurez un clavier
qwerty. Ne changez pas la valeur après -m, qui représente la mémoire du
système. Il semble qu'elle soit hardcodée quelque part et une autre
valeur vous empêchera de démarrer.</p>
<pre class="literal-block">
qemu-system-arm -kernel kernel-qemu -cpu arm1176 -m 256 -M versatilepb -append "root=/dev/sda2 panic=1 init=/bin/sh rw" -hda 2014-01-07-wheezy-raspbian.img
</pre>
<p>Éditez le fichiers /etc/ld.so.preload et commentez la première ligne
(maj + 3 pour faire un #) :</p>
<pre class="literal-block">
nano /etc/ld.so.preload
</pre>
<p>Puis Ctlr-O pour sauvegarder et Ctrl-X pour quitter. Ce changement évite
le chargement de libcofi_rpi.so ce qui évite une boucle inifinie au
boot.</p>
<p>Ensuite, on prépare les disques pour une utilisation future en créant
/etc/udev/rules.d/90-qemu.rules. Entrez les lignes suivantes dans ce
fichier :</p>
<pre class="literal-block">
KERNEL=="sda", SYMLINK+="mmcblk0"
KERNEL=="sda?", SYMLINK+="mmcblk0p%n",
</pre>
<p>Terminez avec la commande sync pour être sûr que tout est écrit sur
l'image. Éditez également votre /etc/fstab : changez <em>mmcblk0p1 et
mmcblk0p2</em>en respectivement <em>sda1</em> et <em>sda2</em>.</p>
</div>
<div class="section" id="demarrage-normal">
<h2>Démarrage normal</h2>
<p>Entrez :</p>
<pre class="literal-block">
qemu-system-arm -kernel kernel-qemu -cpu arm1176 -m 256 -M versatilepb -append "root=/dev/sda2 panic=1" -hda 2014-01-07-wheezy-raspbian.img
</pre>
<p>Si qemu vous demande de lancer fsck, entrez :</p>
<pre class="literal-block">
fsck /dev/sda2 && shutdown -r now
</pre>
<p>Qemu devrait démarrer sur raspiconfig. Sélectionnez directement
<em>Finish</em>. Nous allons maintenant agrandir les partitions. Avec</p>
<pre class="literal-block">
sudo cfdisk /dev/sdb
</pre>
<p>Supprimez la deuxième partition et recréez là avec tout l'espace
disponible. Ensuite, lancez (si les commandes ratent, redémarrez et
relancez les) :</p>
<pre class="literal-block">
sudo resize2fs /dev/sdb2
sudo fsck -f /dev/sdb2
sudo halt
</pre>
<p>C'est fini.</p>
</div>
Relier sa Raspberry Pi à son PC directement en Ethernet2014-01-12T00:00:00+01:002014-01-12T00:00:00+01:00Julien Enselmetag:www.jujens.eu,2014-01-12:/posts/2014/Jan/12/relier-rpi-pc-ethernet/<p>Dans cet article, nous allons étudier comment connecter son Raspberry Pi
directement à son PC pour</p>
<ul class="simple">
<li>pouvoir s'y connecter en SSH</li>
<li>qu'il ait une connection internet (via le wifi de notre PC)</li>
</ul>
<div class="contents topic" id="sommaire">
<p class="topic-title">Sommaire</p>
<ul class="simple">
<li><a class="reference internal" href="#configurer-le-reseau" id="id1">Configurer le réseau</a><ul>
<li><a class="reference internal" href="#methode-graphique-avec-networkmanager" id="id2">Méthode graphique avec NetworkManager</a></li>
<li><a class="reference internal" href="#en-ligne-de-commande" id="id3">En ligne de commande</a></li>
</ul>
</li>
<li><a class="reference internal" href="#configurer-le-pare-feu" id="id4">Configurer le pare feu</a></li>
<li><a class="reference internal" href="#configurons-la-raspberry-pi-pour-le-reseau" id="id5">Configurons la …</a></li></ul></div><p>Dans cet article, nous allons étudier comment connecter son Raspberry Pi
directement à son PC pour</p>
<ul class="simple">
<li>pouvoir s'y connecter en SSH</li>
<li>qu'il ait une connection internet (via le wifi de notre PC)</li>
</ul>
<div class="contents topic" id="sommaire">
<p class="topic-title">Sommaire</p>
<ul class="simple">
<li><a class="reference internal" href="#configurer-le-reseau" id="id1">Configurer le réseau</a><ul>
<li><a class="reference internal" href="#methode-graphique-avec-networkmanager" id="id2">Méthode graphique avec NetworkManager</a></li>
<li><a class="reference internal" href="#en-ligne-de-commande" id="id3">En ligne de commande</a></li>
</ul>
</li>
<li><a class="reference internal" href="#configurer-le-pare-feu" id="id4">Configurer le pare feu</a></li>
<li><a class="reference internal" href="#configurons-la-raspberry-pi-pour-le-reseau" id="id5">Configurons la Raspberry Pi pour le réseau</a><ul>
<li><a class="reference internal" href="#avec-un-serveur-dhcp" id="id6">Avec un serveur DHCP</a></li>
<li><a class="reference internal" href="#pour-une-ip-fixe" id="id7">Pour une IP fixe</a></li>
<li><a class="reference internal" href="#pidora" id="id8">Pidora</a></li>
<li><a class="reference internal" href="#raspbian" id="id9">Raspbian</a></li>
</ul>
</li>
<li><a class="reference internal" href="#et-voila" id="id10">Et voilà</a></li>
<li><a class="reference internal" href="#en-plus" id="id11">En plus</a></li>
<li><a class="reference internal" href="#sources" id="id12">Sources</a></li>
</ul>
</div>
<div class="section" id="configurer-le-reseau">
<h2><a class="toc-backref" href="#id1">Configurer le réseau</a></h2>
<p>Le Raspberry Pi et le PC doivent être sur la même plage d'adresse IP
pour pouvoir communiquer mais pas sur la même plage d'adresse que
l'interface wifi (sinon il y a conflit). Dans la suite, je vais
configurer les interfaces éthernet sur 192.168.1.* le wifi étant géré
automatiquement par votre gestionnaire habituel (NetworkManager chez
moi). Je ne détaillerai que la connexion en IP fixe qui fonctionne très
bien mais qui peux être lourde si vous avez beaucoup de machine à
configurer. Il vous faudra alors regarder comment installer un <a class="reference external" href="http://fr.wikipedia.org/wiki/DHCP">serveur
DHCP</a> par exemple en suivant les
instructions données
<a class="reference external" href="http://doc.fedora-fr.org/wiki/Mise_en_place_d%27un_serveur_DHCP_Simple">ici</a>.</p>
<div class="section" id="methode-graphique-avec-networkmanager">
<h3><a class="toc-backref" href="#id2">Méthode graphique avec NetworkManager</a></h3>
<p><a class="reference external" href="http://fr.wikipedia.org/wiki/NetworkManager">NetworkManager</a> permet
de gérer les réseaux plutôt facilement. Ouvrez la fenêtre de
configuration et cliquez sur <em>réseaux filaires</em>. Choisissez <em>Ajoutez un
profil</em>. Dans la section <em>Identité</em>, donnez un nom au profil et cochez
<em>Connecter automatiquement</em>. Dans la section <em>IPV4</em>, changez <em>Automatic
(DHCP)</em> en <em>Manuel</em>. Entrez l'adresse IP que vous désirez associer à
cette interface. Dans mon cas : 192.168.1.1, le masque de sous réseau :
255.255.255 et la route par défaut : 192.168.1.1.</p>
<p>Cochez <em>Use this connection only for resources on its network.</em></p>
<p>Enregistrez et activez cette interface.</p>
</div>
<div class="section" id="en-ligne-de-commande">
<h3><a class="toc-backref" href="#id3">En ligne de commande</a></h3>
<pre class="code bash literal-block">
sudo ip addr add <span class="m">192</span>.168.1.1/24 dev eth0
</pre>
</div>
</div>
<div class="section" id="configurer-le-pare-feu">
<h2><a class="toc-backref" href="#id4">Configurer le pare feu</a></h2>
<p>Il faut maintenant autoriser la connexion et rediriger le traffic de la
raspberry pi vers l'interface wifi. Pour cela, on entre les commandes
suivantes :</p>
<pre class="code literal-block">
sudo iptables -A FORWARD -o wlan0 -i eth0 -s 192.168.1.0/24 -m conntrack --ctstate NEW -j ACCEPT
sudo iptables -A FORWARD -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
sudo iptables -A POSTROUTING -t nat -j MASQUERADE
</pre>
<p>Ou sous Fedora (ou tout autre système utilisant firewalld)</p>
<pre class="literal-block">
firewall-cmd --zone=public --add-masquerade
</pre>
<p>À titre d'information : sous Fedora, les trois commandes précédentes
permettent de se connecter en SSH à la Raspberry Pi, de pinger une IP
depuis la Raspberry Pi mais pas un nom de domaine. Après un certain
temps à chercher du côté du resolv.conf, c'est grâce à la commande <em>dig
centrale-marseille.fr @8.8.8.8</em> que j'ai pu voir que le problème était
d'un autre ordre. Étrangement cette commande ne vient pas par défaut
sous <a class="reference external" href="http://raspbian.org/">Raspbian</a>. Elle est en revanche présente
sous <a class="reference external" href="http://pidora.ca/">Pidora</a>.</p>
<p>Si vous rencontrez des problèmes, sachez que la commande <em>iptables -F</em>
enlève toutes les règles du parefeu.</p>
<p>Pensez également à vérifier que votre système autorise le transfert d'IP</p>
<pre class="literal-block">
sysctl -a | grep ip_forward
</pre>
<p>Si la réponse est :</p>
<pre class="literal-block">
net.ipv4.ip_forward = 0
</pre>
<p>faîtes, pour autoriser ce paramétrage :</p>
<pre class="literal-block">
sysctl net.ipv4.ip_forward = 1
</pre>
</div>
<div class="section" id="configurons-la-raspberry-pi-pour-le-reseau">
<h2><a class="toc-backref" href="#id5">Configurons la Raspberry Pi pour le réseau</a></h2>
<p>Il y a deux méthodes pour avoir du réseau : l'IP fixe qui implique de
configurer la Raspberry Pi et l'IP attribuée par un serveur DHCP qui
tourne sur votre machine (ce qui implique de le configurer mais permet
d'installer sa rapsberry pi sans écran).</p>
<div class="section" id="avec-un-serveur-dhcp">
<h3><a class="toc-backref" href="#id6">Avec un serveur DHCP</a></h3>
<p>Installez le paquet dhcp qui devrait être présent dans les dépôts de
votre distribution. Éditez ensuite le fichier /etc/dhcp/dhcpd.conf. Il
doit ressembler à :</p>
<pre class="code nginx literal-block">
<span class="c1">#
# DHCP Server Configuration file.
# see /usr/share/doc/dhcp/dhcpd.conf.example
# see dhcpd.conf(5) man page
#
</span><span class="k">subnet</span> <span class="mi">192</span><span class="s">.168.1.0</span> <span class="s">netmask</span> <span class="mi">255</span><span class="s">.255.255.0</span> <span class="p">{</span>
<span class="kn">option</span> <span class="s">routers</span> <span class="mi">192</span><span class="s">.168.1.1</span><span class="p">;</span> <span class="c1"># passerelle par défaut
</span> <span class="kn">option</span> <span class="s">domain-name-servers</span> <span class="mi">8</span><span class="s">.8.8.8</span><span class="p">;</span><span class="c1"># serveurs DNS
</span> <span class="kn">range</span> <span class="mi">192</span><span class="s">.168.1.2</span> <span class="mi">192</span><span class="s">.168.1.100</span><span class="p">;</span> <span class="c1"># plage d’adresse
</span><span class="p">}</span>
</pre>
<p>Pour donner une adresse fixe à un hôte (l'adresse mac est requise) :</p>
<pre class="code nginx literal-block">
<span class="k">subnet</span> <span class="mi">192</span><span class="s">.168.1.0</span> <span class="s">netmask</span> <span class="mi">255</span><span class="s">.255.255.0</span> <span class="p">{</span>
<span class="kn">option</span> <span class="s">routers</span> <span class="mi">192</span><span class="s">.168.1.1</span><span class="p">;</span> <span class="c1"># passerelle par défaut
</span> <span class="kn">option</span> <span class="s">domain-name-servers</span> <span class="mi">8</span><span class="s">.8.8.8</span><span class="p">;</span><span class="c1"># serveurs DNS
</span> <span class="kn">host</span> <span class="s">daneel.egab</span> <span class="p">{</span>
<span class="kn">hardware</span> <span class="s">ethernet</span> <span class="n">b8</span><span class="p">:</span><span class="mi">27</span><span class="p">:</span><span class="n">eb</span><span class="p">:</span><span class="mi">44</span><span class="p">:</span><span class="s">ca:ee</span><span class="p">;</span>
<span class="kn">fixed-address</span> <span class="mi">192</span><span class="s">.168.1.3</span><span class="p">;</span>
<span class="p">}</span>
<span class="kn">range</span> <span class="mi">192</span><span class="s">.168.1.2</span> <span class="mi">192</span><span class="s">.168.1.100</span><span class="p">;</span> <span class="c1"># plage d’adresse
</span><span class="p">}</span>
</pre>
<p>Le bloc host qui donne l'ip fixe doit être avant la directive range</p>
<p>Il n'y a plus qu'à lancer le serveur dhcp avec la commande
<tt class="docutils literal">systemctl start dhcpd</tt>. Pour savoir quelle est l'adresse atribuée à
la Raspberry, consultez les log : <tt class="docutils literal">journalctl <span class="pre">-f</span> /usr/sbin/dhcpd</tt> ou
<tt class="docutils literal">tail <span class="pre">-f</span> /var/log/messages</tt> si vous n'utilisez pas journald.</p>
</div>
<div class="section" id="pour-une-ip-fixe">
<h3><a class="toc-backref" href="#id7">Pour une IP fixe</a></h3>
<p>Mainteant, au tour de la Raspberry Pi de recevoir sa conf.</p>
</div>
<div class="section" id="pidora">
<h3><a class="toc-backref" href="#id8">Pidora</a></h3>
<p>Ouvrez /etc/sysconfig/network-scripts/ifcfg-eth0 et entrez (remplacez
les instructions déjà présentes au besoin) :</p>
<pre class="literal-block">
DEVICE=eth0
BOOTPROTO=none
BROADCAST=192.168.1.255
ONBOOT=yes
USERCTL=no
DNS=8.8.8.8
PEERDNS=yes
IPV6INIT=no
NM_CONTROLLED=no
NETMASK=255.255.255.0
IPADDR=192.168.1.2
GATEWAY=192.168.1.1
TYPE=Ethernet
</pre>
</div>
<div class="section" id="raspbian">
<h3><a class="toc-backref" href="#id9">Raspbian</a></h3>
<p>Ouvrez /etc/network/interfaces et entrez (en ne modifiant que les lignes
concernant l'interface eth0) :</p>
<pre class="literal-block">
auto eth0
iface eth0 inet static
address 192.0.2.7
netmask 255.255.255.0
gateway 192.0.2.254
dns-nameservers 8.8.8.8
</pre>
</div>
</div>
<div class="section" id="et-voila">
<h2><a class="toc-backref" href="#id10">Et voilà</a></h2>
<p>Normalement tout fonctionne. J'espère que cet article vous a été utile.
Si vous avez des questions ou des remarques, n'hésitez pas ;-).</p>
<p>Si vous avez des problèmes avec la résolutions des noms de domaine,
entrez dans /etc/resolv.conf</p>
<pre class="literal-block">
nameserver 8.8.8.8
</pre>
</div>
<div class="section" id="en-plus">
<h2><a class="toc-backref" href="#id11">En plus</a></h2>
<ul class="simple">
<li><a class="reference external" href="//www.jujens.eu/posts/2015/Nov/08/rpi-wifi/">Se connecter en wifi à une raspberry pi</a></li>
</ul>
</div>
<div class="section" id="sources">
<h2><a class="toc-backref" href="#id12">Sources</a></h2>
<ul class="simple">
<li><a class="reference external" href="https://fedoraproject.org/wiki/FirewallD">https://fedoraproject.org/wiki/FirewallD</a></li>
<li><a class="reference external" href="http://wiki.archlinux.fr/Partage_de_connexion">http://wiki.archlinux.fr/Partage_de_connexion</a></li>
<li><a class="reference external" href="https://gist.github.com/ChickenProp/3037292">https://gist.github.com/ChickenProp/3037292</a></li>
</ul>
</div>
Communication série facile avec python2014-01-11T00:00:00+01:002014-05-09T16:00:00+02:00Julien Enselmetag:www.jujens.eu,2014-01-11:/posts/2014/Jan/11/communication-serie-facile-python/<p>Python permet de réaliser facilement une liaison via USB entre un PC et
une carte arduino. Nous allons l'illustrer par un exemple qui lit ce
qu'une Arduino Uno envoie et un autre qui envoie un nombre à la Arduino.
La diode de celle-ci doit alors clignoter du nombre envoyé.</p>
<p>Il …</p><p>Python permet de réaliser facilement une liaison via USB entre un PC et
une carte arduino. Nous allons l'illustrer par un exemple qui lit ce
qu'une Arduino Uno envoie et un autre qui envoie un nombre à la Arduino.
La diode de celle-ci doit alors clignoter du nombre envoyé.</p>
<p>Il faut uploader le code suivant sur votre carte Arduino :</p>
<pre class="code cpp literal-block">
<span class="cp">#define LED_PIN 13
</span><span class="kt">void</span> <span class="nf">setup</span><span class="p">()</span>
<span class="p">{</span>
<span class="n">pinMode</span><span class="p">(</span><span class="n">ledPin</span><span class="p">,</span> <span class="n">OUTPUT</span><span class="p">);</span>
<span class="n">Serial</span><span class="p">.</span><span class="n">begin</span><span class="p">(</span><span class="mi">9600</span><span class="p">);</span>
<span class="p">}</span>
<span class="kt">void</span> <span class="nf">loop</span><span class="p">()</span>
<span class="p">{</span>
<span class="n">Serial</span><span class="p">.</span><span class="n">println</span><span class="p">(</span><span class="s">"Bonjour"</span><span class="p">);</span>
<span class="n">Serial</span><span class="p">.</span><span class="n">println</span><span class="p">(</span><span class="s">"C'est la carte Arduino qui parle"</span><span class="p">);</span>
<span class="k">while</span><span class="p">(</span><span class="n">Serial</span><span class="p">.</span><span class="n">available</span><span class="p">())</span> <span class="p">{</span>
<span class="kt">int</span> <span class="n">lu</span> <span class="o">=</span> <span class="n">Serial</span><span class="p">.</span><span class="n">read</span><span class="p">();</span>
<span class="n">flash</span><span class="p">(</span><span class="n">lu</span><span class="p">);</span>
<span class="p">}</span>
<span class="n">delay</span><span class="p">(</span><span class="mi">1000</span><span class="p">);</span>
<span class="p">}</span>
<span class="kt">void</span> <span class="nf">flash</span><span class="p">(</span><span class="kt">int</span> <span class="n">n</span><span class="p">)</span>
<span class="p">{</span>
<span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span> <span class="o"><</span> <span class="n">n</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span>
<span class="p">{</span>
<span class="n">digitalWrite</span><span class="p">(</span><span class="n">ledPin</span><span class="p">,</span> <span class="n">HIGH</span><span class="p">);</span>
<span class="n">delay</span><span class="p">(</span><span class="mi">1000</span><span class="p">);</span>
<span class="n">digitalWrite</span><span class="p">(</span><span class="n">ledPin</span><span class="p">,</span> <span class="n">LOW</span><span class="p">);</span>
<span class="n">delay</span><span class="p">(</span><span class="mi">1000</span><span class="p">);</span>
<span class="p">}</span>
<span class="p">}</span>
</pre>
<p>Pour la lecture de ce qu'envoie la Arduino :</p>
<pre class="code python literal-block">
<span class="c1"># Module de lecture/ecriture du port série</span>
<span class="kn">from</span> <span class="nn">serial</span> <span class="kn">import</span> <span class="o">*</span>
<span class="c1"># Port série ttyACM0</span>
<span class="c1"># Vitesse de baud : 9600</span>
<span class="c1"># Timeout en lecture : 1 sec</span>
<span class="c1"># Timeout en écriture : 1 sec</span>
<span class="k">with</span> <span class="n">Serial</span><span class="p">(</span><span class="n">port</span><span class="o">=</span><span class="s2">"/dev/ttyACM0"</span><span class="p">,</span> <span class="n">baudrate</span><span class="o">=</span><span class="mi">9600</span><span class="p">,</span> <span class="n">timeout</span><span class="o">=</span><span class="mi">1</span><span class="p">,</span> <span class="n">writeTimeout</span><span class="o">=</span><span class="mi">1</span><span class="p">)</span> <span class="k">as</span> <span class="n">port_serie</span><span class="p">:</span>
<span class="k">if</span> <span class="n">port_serie</span><span class="o">.</span><span class="n">isOpen</span><span class="p">():</span>
<span class="k">while</span> <span class="kc">True</span><span class="p">:</span>
<span class="n">ligne</span> <span class="o">=</span> <span class="n">port_serie</span><span class="o">.</span><span class="n">read_line</span><span class="p">()</span>
<span class="nb">print</span> <span class="n">ligne</span>
</pre>
<p>Pour l'envoie de données vers la Arduino, <em>en python2</em> :</p>
<pre class="code python literal-block">
<span class="kn">from</span> <span class="nn">serial</span> <span class="kn">import</span> <span class="o">*</span>
<span class="n">nombre</span> <span class="o">=</span> <span class="n">raw_input</span><span class="p">(</span><span class="s2">"Entrez un nombre : "</span><span class="p">)</span>
<span class="n">port_serie</span><span class="o">.</span><span class="n">write</span><span class="p">([</span><span class="n">nombre</span><span class="p">])</span>
</pre>
<p>Notez qu'il est possible d'envoyer un plusieurs nombres à la suite au
port série, puisque la fonction "serial.write()" en Python prend en
argument un tableau d'entiers.</p>
<p>Pareil <em>en python3</em> :</p>
<pre class="code python literal-block">
<span class="kn">from</span> <span class="nn">serial</span> <span class="kn">import</span> <span class="o">*</span>
<span class="n">nombre</span> <span class="o">=</span> <span class="nb">input</span><span class="p">(</span><span class="s2">"Entrez un nombre : "</span><span class="p">)</span>
<span class="n">port_serie</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="n">nombre</span><span class="o">.</span><span class="n">encode</span><span class="p">(</span><span class="s1">'ascii'</span><span class="p">))</span>
</pre>
<p>La différence entre le code python2 et python3 vient du fait qu'en python3, les
communications réseaux et série doivent se faire avec des objets de type
<tt class="docutils literal">bytes</tt> (chaîne d'octet). De même, les données reçues précédemment sont de
type <tt class="docutils literal">bytes</tt> en python3 mais de type <tt class="docutils literal">str</tt> (chaîne de caractère) en python2.
Voir par <a class="reference external" href="http://python.developpez.com/cours/apprendre-python3/?page=page_12#L12-A-9">là</a>
pour plus d'infos.</p>