<?xml 
version="1.0" encoding="utf-8"?><?xml-stylesheet title="XSL formatting" type="text/xsl" href="https://modelleisenbahn.triskell.org/spip.php?page=backend.xslt" ?>
<rss version="2.0" 
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:atom="http://www.w3.org/2005/Atom"
>

<channel xml:lang="fr">
	<title>ModelleisenbahN</title>
	<link>https://modelleisenbahn.triskell.org/</link>
	<description>Modelleisenbahn traite de la construction de mon r&#233;seau &#171; Messingrohrstadt &#187;, r&#233;seau allemand de l'&#233;poque II. Des documents sur le th&#232;me de la SNCF et &#233;labor&#233;s par R&#233;my Fauvet sont &#233;galement h&#233;berg&#233;s.</description>
	<language>fr</language>
	<generator>SPIP - www.spip.net</generator>
	<atom:link href="https://modelleisenbahn.triskell.org/spip.php?id_mot=4&amp;page=backend" rel="self" type="application/rss+xml" />

	<image>
		<title>ModelleisenbahN</title>
		<url>https://modelleisenbahn.triskell.org/local/cache-vignettes/L144xH144/siteon0-d64b7.png?1692197123</url>
		<link>https://modelleisenbahn.triskell.org/</link>
		<height>144</height>
		<width>144</width>
	</image>



<item xml:lang="fr">
		<title>Am&#233;lioration et m&#233;morisation des r&#233;glages</title>
		<link>https://modelleisenbahn.triskell.org/spip.php?article67</link>
		<guid isPermaLink="true">https://modelleisenbahn.triskell.org/spip.php?article67</guid>
		<dc:date>2013-12-02T07:45:39Z</dc:date>
		<dc:format>text/html</dc:format>
		<dc:language>fr</dc:language>
		<dc:creator>Jean-Luc</dc:creator>


		<dc:subject>aiguille</dc:subject>
		<dc:subject>servo</dc:subject>
		<dc:subject>Arduino</dc:subject>

		<description>
&lt;p&gt;Comme indiqu&#233; dans la vid&#233;o au bas de l'article &#171; R&#233;glage des but&#233;es des servomoteurs &#187;, un probl&#232;me li&#233; &#224; l'inertie m&#233;canique subsiste. Nous avons aussi le probl&#232;me de la non m&#233;morisation des r&#233;glages. Nous allons voir comment r&#233;gler ces deux probl&#232;mes. &lt;br class='autobr' /&gt;
Prise en compte de l'inertie m&#233;canique &lt;br class='autobr' /&gt;
Quand la consigne de position, via la dur&#233;e de l'&#233;tat haut de la PWM, est envoy&#233; au servomoteur, celui-ci met quelques instants &#224; appliquer cette consigne. Or, le programme actuel coupe la PWM est (&#8230;)&lt;/p&gt;


-
&lt;a href="https://modelleisenbahn.triskell.org/spip.php?rubrique22" rel="directory"&gt;Man&#339;uvre des aiguilles avec des servo-moteurs&lt;/a&gt;

/ 
&lt;a href="https://modelleisenbahn.triskell.org/spip.php?mot4" rel="tag"&gt;aiguille&lt;/a&gt;, 
&lt;a href="https://modelleisenbahn.triskell.org/spip.php?mot5" rel="tag"&gt;servo&lt;/a&gt;, 
&lt;a href="https://modelleisenbahn.triskell.org/spip.php?mot10" rel="tag"&gt;Arduino&lt;/a&gt;

		</description>


 <content:encoded>&lt;div class='rss_texte'&gt;&lt;p&gt;Comme indiqu&#233; dans la vid&#233;o au bas de l'article &#171; &lt;a href='https://modelleisenbahn.triskell.org/spip.php?article65' class=&#034;spip_in&#034;&gt;R&#233;glage des but&#233;es des servomoteurs&lt;/a&gt; &#187;, un probl&#232;me li&#233; &#224; l'inertie m&#233;canique subsiste. Nous avons aussi le probl&#232;me de la non m&#233;morisation des r&#233;glages. Nous allons voir comment r&#233;gler ces deux probl&#232;mes.&lt;/p&gt;
&lt;h2 class=&#034;spip&#034;&gt;Prise en compte de l'inertie m&#233;canique&lt;/h2&gt;
&lt;p&gt;Quand la consigne de position, via la dur&#233;e de l'&#233;tat haut de la PWM, est envoy&#233; au servomoteur, celui-ci met quelques instants &#224; appliquer cette consigne. Or, le programme actuel coupe la PWM est appelant la fonction &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;detach()&lt;/code&gt; d&#232;s que la consigne atteint l'angle maximum ou l'angle minimum. Le servo n'a donc pas le temps de r&#233;pondre &#224; cette consigne et pour r&#233;gler le probl&#232;me il faut diff&#233;rer le d&#233;tachement du servo.&lt;/p&gt;
&lt;p&gt;Au lieu de d&#233;tacher imm&#233;diatement le servo, il faut initialiser un compteur, que nous appelleront &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;cptArret&lt;/code&gt;, qui quand il atteint 0 provoque le d&#233;tachement du servo. Une fois le servo d&#233;tach&#233;, le compteur est mis &#224; -1 pour &#233;viter de d&#233;tacher le servo de mani&#232;re r&#233;p&#233;titive. Actuellement dans &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;gereServo()&lt;/code&gt; en plusieurs endroits, la vitesse est mise &#224; 0 et le servo est d&#233;tach&#233;.&lt;/p&gt;
&lt;p&gt;Il faut remplacer les &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;objetServo.detach()&lt;/code&gt; par l'initialisation du compteur. Pour rationaliser nous allons mettre le &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;vitesse = 0;&lt;/code&gt; et l'initialisation du compteur dans une fonction membre s&#233;par&#233;e :&lt;/p&gt;
&lt;div class=&#034;precode&#034;&gt;&lt;pre data-raccourci=&#034;code&#034; data-language=&#034;cpp&#034; class='spip_code spip_code_block language-cpp' dir='ltr' style='text-align:left;'&gt;&lt;code&gt;void arreteServo() { vitesse = 0; cptArret = 30; } &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Avec le d&#233;lai de 5ms dans &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;loop()&lt;/code&gt;, une valeur de 30 engendre un d&#233;lai de 150ms ce qui est suffisant pour que la m&#233;canique rattrape l'&#233;lectronique.&lt;/p&gt;
&lt;p&gt;Il faut maintenant, dans la fonction &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;gereServo()&lt;/code&gt;, d&#233;cr&#233;menter ce compteur tant qu'il est &#8805; &#224; 0 et d&#233;tacher le servo quand ce compteur est &#233;gal &#224; 0. De plus, &#224; chaque fois que nous avons la mise de la vitesse &#224; 0 et le d&#233;tachement du servo, nous le rempla&#231;ons par l'appel &#224; la fonction &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;arreteServo()&lt;/code&gt;. &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;gereServo()&lt;/code&gt; devient :&lt;/p&gt;
&lt;div class=&#034;precode&#034;&gt;&lt;pre data-raccourci=&#034;code&#034; data-language=&#034;cpp&#034; class='spip_code spip_code_block language-cpp' dir='ltr' style='text-align:left;'&gt;&lt;code&gt;void gereServo() { objetServo.writeMicroseconds(angle); if (vitesse == 0) { if (cptArret == 0) objetServo.detach(); if (cptArret &gt;= 0) cptArret--; } else angle += vitesse; if (! reglageEnCours || etatServo == SERVO_EN_MOUVEMENT_VERS_ANGLE_MIN || etatServo == SERVO_EN_MOUVEMENT_VERS_ANGLE_MAX) { if (angle &gt; angleMax) { angle = angleMax; arreteServo(); etatServo = SERVO_A_ANGLE_MAX; } else if (angle &lt; angleMin) { angle = angleMin; arreteServo(); etatServo = SERVO_A_ANGLE_MIN; } } else { if (etatServo == SERVO_A_ANGLE_MIN) { if (vitesse &gt; 0 &amp;&amp; angle &gt;= angleMin) { angle = angleMin; arreteServo(); } else if (vitesse &lt; 0 &amp;&amp; angle &lt;= angleMin) { angle = angleMin; arreteServo(); } } else if (etatServo == SERVO_A_ANGLE_MAX) { if (vitesse &gt; 0 &amp;&amp; angle &gt;= angleMax) { angle = angleMax; arreteServo(); } else if (vitesse &lt; 0 &amp;&amp; angle &lt;= angleMax) { angle = angleMax; arreteServo(); } } } }&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Il faut &#233;galement garantir que le servo ne sera pas d&#233;tach&#233; intempestivement. En effet, si l'utilisateur demande un mouvement du servo dans l'intervalle de temps entre le passage de la vitesse &#224; 0 et le passage du compteur &#224; 0, il faut passer directement le compteur &#224; -1 dans &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;evenementServo()&lt;/code&gt; car sinon le d&#233;tachement du servo interviendra pendant le mouvement, ce qui est un dysfonctionnement.&lt;/p&gt;
&lt;h2 class=&#034;spip&#034;&gt;M&#233;morisation des but&#233;es&lt;/h2&gt;
&lt;p&gt;La plupart des microcontr&#244;leurs dispose d'une m&#233;moire permanente, c'est &#224; dire qui ne s'efface pas &#224; la mise hors tension, sous forme d'EEPROM (Electrically Erasable Programmable Read-Only Memory). La biblioth&#232;que de l'Arduino permet de lire et d'&#233;crire l'EEPROM de mani&#232;re tr&#232;s simple via deux fonctions : &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;EEPROM.read(...)&lt;/code&gt; et &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;EEPROM.write(..., ...)&lt;/code&gt;. &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;EEPROM.read(...)&lt;/code&gt; prend comme argument une adresse d'octet (byte) et retourne l'octet qui se trouve &#224; cet adresse et &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;EEPROM.write(..., ...)&lt;/code&gt; prend deux arguments. Le premier est l'adresse de l'octet que l'on souhaite &#233;crire et le second est la valeur que l'on souhaite y &#233;crire. L'EEPROM de l'ATMega328 qui &#233;quipe l'Arduino Uno a une taille de 1ko.&lt;/p&gt;
&lt;p&gt;Pour chaque servomoteur, il faut stocker les deux but&#233;es. Chaque but&#233;e est stock&#233;e dans un &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;int&lt;/code&gt;. Sur l'Arduino Uno, un &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;int&lt;/code&gt; prend 2 octets. Par cons&#233;quent il faut 4 octets pour chaque servos et donc 32 octets au total. En d&#233;marrant &#224; l'adresse 0 de l'EEPROM, l'adresse de stockage des but&#233;e d'une servo sera donc &#233;gale au &lt;i&gt;num&#233;ro du servo&lt;/i&gt; &#215; 4. Nous allons donc stocker le premier octet de angleMin &#224; &lt;i&gt;num&#233;ro du servo&lt;/i&gt; &#215; 4, le second &#224; &lt;i&gt;num&#233;ro du servo&lt;/i&gt; &#215; 4 + 1, le premier octet de angleMax &#224; &lt;i&gt;num&#233;ro du servo&lt;/i&gt; &#215; 4 + 2 et le 2e octet &#224; &lt;i&gt;num&#233;ro du servo&lt;/i&gt; &#215; 4 + 3. Nous allons donc ajouter une donn&#233;e membre &#224; la classe &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;DescripteurServo&lt;/code&gt; pour y m&#233;moriser cette adresse. Cette donn&#233;e est initialis&#233;e dans le constructeur.&lt;/p&gt;
&lt;p&gt;Il est n&#233;cessaire d'&#234;tre prudent avec les EEPROM. En effet, elle supporte un nombre de cycle d'effacement/&#233;criture r&#233;duit. Par exemple, celle de l'ATMega328 qui &#233;quipe l'Arduino Uno supporte 100 000 cycles d'effacement/&#233;criture. Cela peut sembler une valeur importante mais si nous &#233;crivons imprudemment les but&#233;es des servos en EEPROM &#224; chaque passage dans &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;loop()&lt;/code&gt;, l'EEPROM sera fichue en 5ms &#215; 100 000 = 500s = 8 minutes et 20 secondes.&lt;/p&gt;
&lt;p&gt;Il faut donc n'&#233;crire les but&#233;es que si un r&#233;glage a &#233;t&#233; effectu&#233; et si la valeur a chang&#233;. Nous allons donc ajouter un bool&#233;en membre de la classe &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;DescripteurServo&lt;/code&gt;, &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;aSauver&lt;/code&gt;, qui sera mis &#224; vrai dans &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;regleServo()&lt;/code&gt; si l'une des but&#233;es a &#233;t&#233; chang&#233;e.&lt;/p&gt;
&lt;p&gt;Enfin, deux fonctions membres, &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;ecrireEEPROMSiDifferent(...)&lt;/code&gt; et &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;enregistre()&lt;/code&gt; sont ajout&#233;es pour m&#233;moriser les but&#233;es dans l'EEPROM. Le travail n'est effectu&#233; que si &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;aSauver&lt;/code&gt; est vrai et si les valeurs ont chang&#233;.&lt;/p&gt;
&lt;div class=&#034;precode&#034;&gt;&lt;pre data-raccourci=&#034;code&#034; data-language=&#034;cpp&#034; class='spip_code spip_code_block language-cpp' dir='ltr' style='text-align:left;'&gt;&lt;code&gt;void ecrireEEPROMSiDifferent(int adresseEcriture, byte valeur) { if (EEPROM.read(adresseEcriture) != valeur) EEPROM.write(adresseEcriture, valeur); } void enregistre() { if (aSauver) { ecrireEEPROMSiDifferent(adresse, angleMin &amp; 0xFF); ecrireEEPROMSiDifferent(adresse + 1, angleMin &gt;&gt; 8); ecrireEEPROMSiDifferent(adresse + 2, angleMax &amp; 0xFF); ecrireEEPROMSiDifferent(adresse + 3, angleMax &gt;&gt; 8); aSauver = false; } }&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Enfin, au d&#233;marrage du syst&#232;me dans &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;connecte()&lt;/code&gt;, il faut initialiser la position des servos aux valeurs enregistr&#233;es. La valeur lue est recadr&#233;e entre ANGLE_MIN et ANGLE_MAX car l'EEPROM peut contenir des valeurs &#233;crites par une autre application ou bien &#234;tre vierge&lt;span class=&#034;spip_note_ref&#034;&gt; [&lt;a href=&#034;#nb1&#034; class=&#034;spip_note&#034; rel=&#034;appendix&#034; title=&#034;Un octet d'EEPROM qui n'a jamais &#233;t&#233; &#233;crit est &#224; la valeur 255 en d&#233;cimal ou (&#8230;)&#034; id=&#034;nh1&#034;&gt;1&lt;/a&gt;]&lt;/span&gt;.&lt;/p&gt;
&lt;div class=&#034;precode&#034;&gt;&lt;pre data-raccourci=&#034;code&#034; data-language=&#034;cpp&#034; class='spip_code spip_code_block language-cpp' dir='ltr' style='text-align:left;'&gt;&lt;code&gt;angleMin = EEPROM.read(adresse) | ((int)EEPROM.read(adresse + 1)) &lt;&lt; 8; angleMax = EEPROM.read(adresse + 2) | ((int)EEPROM.read(adresse + 3)) &lt;&lt; 8; if (angleMin &lt; ANGLE_MIN || angleMin &gt; ANGLE_MAX) angleMin = ANGLE_MIN; if (angleMax &lt; ANGLE_MIN || angleMax &gt; ANGLE_MAX) angleMax = ANGLE_MAX;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Le sketch de l'application am&#233;lior&#233;e&lt;/p&gt;
&lt;div class='spip_document_334 spip_document spip_documents spip_document_file spip_document_avec_legende' data-legende-len=&#034;66&#034; data-legende-lenx=&#034;xx&#034;
&gt;
&lt;figure class=&#034;spip_doc_inner&#034;&gt;
&lt;a href='https://modelleisenbahn.triskell.org/IMG/zip/Huit_boutons_huit_servos_detach_reglage_eeprom_cpp-4.zip' class=&#034; spip_doc_lien&#034; title='Zip - 3.6 kio' type=&#034;application/zip&#034;&gt;&lt;img src='https://modelleisenbahn.triskell.org/local/cache-vignettes/L64xH64/zip-f045b.svg?1772799586' width='64' height='64' alt='' /&gt;&lt;/a&gt;
&lt;figcaption class='spip_doc_legende'&gt; &lt;div class='spip_doc_titre crayon document-titre-334 '&gt;&lt;strong&gt;Sketch Arduino de l'application avec r&#233;glage des but&#233;es am&#233;lior&#233;
&lt;/strong&gt;&lt;/div&gt; &lt;/figcaption&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;p&gt;Et enfin une petite vid&#233;o qui montre l'effet de ces deux am&#233;liorations.&lt;/p&gt;
&lt;div class=&#034;spip_document_331 spip_document spip_documents spip_document_video spip_document_avec_legende&#034; data-legende-len=&#034;66&#034; data-legende-lenx=&#034;xx&#034;
&gt;
&lt;figure class=&#034;spip_doc_inner&#034;&gt;
&lt;div class=&#034;video-intrinsic-wrapper&#034; style='height:0;width:640px;max-width:100%;padding-bottom:56.25%;position:relative;'&gt; &lt;div class=&#034;video-wrapper&#034; style=&#034;position: absolute;top:0;left:0;width:100%;height:100%;&#034;&gt; &lt;video class=&#034;mejs mejs-331&#034; data-id=&#034;9eb5826d230e416a3f3cca7bcaa3eb95&#034; data-mejsoptions='{&#034;iconSprite&#034;: &#034;plugins-dist/medias/lib/mejs/mejs-controls.svg&#034;,&#034;alwaysShowControls&#034;: true,&#034;pluginPath&#034;:&#034;plugins-dist/medias/lib/mejs/&#034;,&#034;loop&#034;:false,&#034;videoWidth&#034;:&#034;100%&#034;,&#034;videoHeight&#034;:&#034;100%&#034;}' width=&#034;100%&#034; height=&#034;100%&#034; controls=&#034;controls&#034; preload=&#034;none&#034; &gt; &lt;source type=&#034;application/x-shockwave-flash&#034; src=&#034;http://www.youtube.com/v/VyTvpKi1KH0?hl=fr_FR&amp;version=3&amp;rel=0&#034; /&gt; &lt;img src='https://modelleisenbahn.triskell.org/local/cache-vignettes/L64xH64/swf-d2c4d-75a7b.svg?1772798901' width='64' height='64' alt='Impossible de lire la video' /&gt; &lt;/video&gt; &lt;/div&gt;
&lt;/div&gt;
&lt;figcaption class='spip_doc_legende'&gt; &lt;div class='spip_doc_titre crayon document-titre-331 '&gt;&lt;strong&gt;D&#233;monstration de l'am&#233;lioration et de la m&#233;morisation des but&#233;es
&lt;/strong&gt;&lt;/div&gt; &lt;/figcaption&gt;
&lt;div class=&#034;base64javascript166586552469cf630e859323.72063725&#034; title=&#034;PHNjcmlwdD4gdmFyIG1lanNwYXRoPSdwbHVnaW5zLWRpc3QvbWVkaWFzL2xpYi9tZWpzL21lZGlhZWxlbWVudC1hbmQtcGxheWVyLm1pbi5qcz8xNzcyNzk1ODQwJyxtZWpzY3NzPSdwbHVnaW5zLWRpc3QvbWVkaWFzL2xpYi9tZWpzL21lZGlhZWxlbWVudHBsYXllci5taW4uY3NzPzE3NzI3OTU4NDAnOwp2YXIgbWVqc2xvYWRlcjsKKGZ1bmN0aW9uKCl7dmFyIGE9bWVqc2xvYWRlcjsidW5kZWZpbmVkIj09dHlwZW9mIGEmJihtZWpzbG9hZGVyPWE9e2dzOm51bGwscGx1Zzp7fSxjc3M6e30saW5pdDpudWxsLGM6MCxjc3Nsb2FkOm51bGx9KTthLmluaXR8fChhLmNzc2xvYWQ9ZnVuY3Rpb24oYyl7aWYoInVuZGVmaW5lZCI9PXR5cGVvZiBhLmNzc1tjXSl7YS5jc3NbY109ITA7dmFyIGI9ZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgibGluayIpO2IuaHJlZj1jO2IucmVsPSJzdHlsZXNoZWV0IjtiLnR5cGU9InRleHQvY3NzIjtkb2N1bWVudC5nZXRFbGVtZW50c0J5VGFnTmFtZSgiaGVhZCIpWzBdLmFwcGVuZENoaWxkKGIpfX0sYS5pbml0PWZ1bmN0aW9uKCl7ITA9PT1hLmdzJiZmdW5jdGlvbihjKXtqUXVlcnkoImF1ZGlvLm1lanMsdmlkZW8ubWVqcyIpLm5vdCgiLmRvbmUsLm1lanNfX3BsYXllciIpLmVhY2goZnVuY3Rpb24oKXtmdW5jdGlvbiBiKCl7dmFyIGU9ITAsaDtmb3IoaCBpbiBkLmNzcylhLmNzc2xvYWQoZC5jc3NbaF0pO2Zvcih2YXIgZiBpbiBkLnBsdWdpbnMpInVuZGVmaW5lZCI9PQp0eXBlb2YgYS5wbHVnW2ZdPyhlPSExLGEucGx1Z1tmXT0hMSxqUXVlcnkuZ2V0U2NyaXB0KGQucGx1Z2luc1tmXSxmdW5jdGlvbigpe2EucGx1Z1tmXT0hMDtiKCl9KSk6MD09YS5wbHVnW2ZdJiYoZT0hMSk7ZSYmalF1ZXJ5KCIjIitjKS5tZWRpYWVsZW1lbnRwbGF5ZXIoalF1ZXJ5LmV4dGVuZChkLm9wdGlvbnMse3N1Y2Nlc3M6ZnVuY3Rpb24oYSxjKXtmdW5jdGlvbiBiKCl7dmFyIGI9alF1ZXJ5KGEpLmNsb3Nlc3QoIi5tZWpzX19pbm5lciIpO2EucGF1c2VkPyhiLmFkZENsYXNzKCJwYXVzaW5nIiksc2V0VGltZW91dChmdW5jdGlvbigpe2IuZmlsdGVyKCIucGF1c2luZyIpLnJlbW92ZUNsYXNzKCJwbGF5aW5nIikucmVtb3ZlQ2xhc3MoInBhdXNpbmciKS5hZGRDbGFzcygicGF1c2VkIil9LDEwMCkpOmIucmVtb3ZlQ2xhc3MoInBhdXNlZCIpLnJlbW92ZUNsYXNzKCJwYXVzaW5nIikuYWRkQ2xhc3MoInBsYXlpbmciKX1iKCk7YS5hZGRFdmVudExpc3RlbmVyKCJwbGF5IixiLCExKTsKYS5hZGRFdmVudExpc3RlbmVyKCJwbGF5aW5nIixiLCExKTthLmFkZEV2ZW50TGlzdGVuZXIoInBhdXNlIixiLCExKTthLmFkZEV2ZW50TGlzdGVuZXIoInBhdXNlZCIsYiwhMSk7Zy5hdHRyKCJhdXRvcGxheSIpJiZhLnBsYXkoKX19KSl9dmFyIGc9alF1ZXJ5KHRoaXMpLmFkZENsYXNzKCJkb25lIiksYzsoYz1nLmF0dHIoImlkIikpfHwoYz0ibWVqcy0iK2cuYXR0cigiZGF0YS1pZCIpKyItIithLmMrKyxnLmF0dHIoImlkIixjKSk7dmFyIGQ9e29wdGlvbnM6e30scGx1Z2luczp7fSxjc3M6W119LGUsaDtmb3IoZSBpbiBkKWlmKGg9Zy5hdHRyKCJkYXRhLW1lanMiK2UpKWRbZV09alF1ZXJ5LnBhcnNlSlNPTihoKTtiKCl9KX0oalF1ZXJ5KX0pO2EuZ3N8fCgidW5kZWZpbmVkIiE9PXR5cGVvZiBtZWpzY3NzJiZhLmNzc2xvYWQobWVqc2NzcyksYS5ncz1qUXVlcnkuZ2V0U2NyaXB0KG1lanNwYXRoLGZ1bmN0aW9uKCl7YS5ncz0hMDthLmluaXQoKTtqUXVlcnkoYS5pbml0KTtvbkFqYXhMb2FkKGEuaW5pdCl9KSl9KSgpOzwvc2NyaXB0Pg==&#034;&gt;&lt;/div&gt; &lt;/figure&gt;
&lt;/div&gt;&lt;/div&gt;
		&lt;hr /&gt;
		&lt;div class='rss_notes'&gt;&lt;div id=&#034;nb1&#034;&gt;
&lt;p&gt;&lt;span class=&#034;spip_note_ref&#034;&gt;[&lt;a href=&#034;#nh1&#034; class=&#034;spip_note&#034; title=&#034;Notes 1&#034; rev=&#034;appendix&#034;&gt;1&lt;/a&gt;] &lt;/span&gt;Un octet d'EEPROM qui n'a jamais &#233;t&#233; &#233;crit est &#224; la valeur 255 en d&#233;cimal ou 0xFF en hexad&#233;cimal (tous les bits de l'octet sont &#224; 1).&lt;/p&gt;
&lt;/div&gt;&lt;/div&gt;
		
		</content:encoded>


		

	</item>
<item xml:lang="fr">
		<title>R&#233;glage des but&#233;es des servomoteurs</title>
		<link>https://modelleisenbahn.triskell.org/spip.php?article65</link>
		<guid isPermaLink="true">https://modelleisenbahn.triskell.org/spip.php?article65</guid>
		<dc:date>2013-12-01T17:09:10Z</dc:date>
		<dc:format>text/html</dc:format>
		<dc:language>fr</dc:language>
		<dc:creator>Jean-Luc</dc:creator>


		<dc:subject>aiguille</dc:subject>
		<dc:subject>servo</dc:subject>
		<dc:subject>Arduino</dc:subject>

		<description>
&lt;p&gt;Nous voici enfin &#224; l'avant derni&#232;re &#233;tape de d&#233;veloppement de notre syst&#232;me. Dans &#171; S&#233;lection d'un servomoteur pour le r&#233;glage des but&#233;es &#187;, nous avons vu la mise en &#339;uvre d'un codeur pour d&#233;signer le servomoteur &#224; r&#233;gler, dans &#171; Clavier de r&#233;glage des but&#233;es &#187;, nous avons vu l'ajout d'un second clavier analogique destin&#233; &#224; permettre le r&#233;glage des but&#233;es et, comme nous avions d&#233;j&#224; un clavier analogique, la g&#233;n&#233;ralisation de la gestion de ce type de clavier par le biais d'une classe C++. (&#8230;)&lt;/p&gt;


-
&lt;a href="https://modelleisenbahn.triskell.org/spip.php?rubrique22" rel="directory"&gt;Man&#339;uvre des aiguilles avec des servo-moteurs&lt;/a&gt;

/ 
&lt;a href="https://modelleisenbahn.triskell.org/spip.php?mot4" rel="tag"&gt;aiguille&lt;/a&gt;, 
&lt;a href="https://modelleisenbahn.triskell.org/spip.php?mot5" rel="tag"&gt;servo&lt;/a&gt;, 
&lt;a href="https://modelleisenbahn.triskell.org/spip.php?mot10" rel="tag"&gt;Arduino&lt;/a&gt;

		</description>


 <content:encoded>&lt;div class='rss_texte'&gt;&lt;p&gt;Nous voici enfin &#224; l'avant derni&#232;re &#233;tape de d&#233;veloppement de notre syst&#232;me. Dans &#171; &lt;a href='https://modelleisenbahn.triskell.org/spip.php?article61' class=&#034;spip_in&#034;&gt;S&#233;lection d'un servomoteur pour le r&#233;glage des but&#233;es&lt;/a&gt; &#187;, nous avons vu la mise en &#339;uvre d'un codeur pour d&#233;signer le servomoteur &#224; r&#233;gler, dans &#171; &lt;a href='https://modelleisenbahn.triskell.org/spip.php?article62' class=&#034;spip_in&#034;&gt;Clavier de r&#233;glage des but&#233;es&lt;/a&gt; &#187;, nous avons vu l'ajout d'un second clavier analogique destin&#233; &#224; permettre le r&#233;glage des but&#233;es et, comme nous avions d&#233;j&#224; un clavier analogique, la g&#233;n&#233;ralisation de la gestion de ce type de clavier par le biais d'une classe C++.&lt;/p&gt;
&lt;p&gt;Nous allons maintenant voir comment int&#233;grer cette fonction de r&#233;glage au programme de pilotage des 8 servos. Mais tout d'abord quelques &#233;claircissement sur la fonction d&#233;sir&#233;e.&lt;/p&gt;
&lt;h2 class=&#034;spip&#034;&gt;Le fonctionnement du r&#233;glage&lt;/h2&gt;
&lt;p&gt;Lorsqu'un des servo est d&#233;sign&#233; au moyen du codeur, le mouvement des servos restent actif. En effet, le r&#233;glage ne porte que sur la but&#233;e actuelle du servo d&#233;sign&#233;.&lt;/p&gt;
&lt;p&gt;Si le servo est en but&#233;e dans le sens horaire, une pression sur le poussoir de droite doit d&#233;placer la but&#233;e horaire un peu plus dans le sens horaire. Une pression sur le poussoir de gauche d&#233;place la but&#233;e un peu moins. De m&#234;me, si le servo est en but&#233;e dans le sens trigonom&#233;trique, une pression sur le poussoir de gauche d&#233;place un peu plus la but&#233;e dans le sens trigonom&#233;trique et une pression sur le poussoir de droite un peu moins.&lt;/p&gt;
&lt;p&gt;Pour passer du r&#233;glage d'une but&#233;e au r&#233;glage de l'autre but&#233;e, il suffit de presser le poussoir commandant le mouvement du servomoteur.&lt;/p&gt;
&lt;p&gt;Une tentative de r&#233;glage alors que le servo est en mouvement est ignor&#233;e.&lt;/p&gt;
&lt;p&gt;Le r&#233;glage en lui m&#234;me va donc augmenter ou diminuer les angles minimum et maximum. Si on veut un r&#233;glage pr&#233;cis, il faut r&#233;gler de pas en pas&lt;span class=&#034;spip_note_ref&#034;&gt; [&lt;a href=&#034;#nb1&#034; class=&#034;spip_note&#034; rel=&#034;appendix&#034; title=&#034;Un pas vaut 1&#181;s puisqu'on utilise la fonction pour piloter les servos&#034; id=&#034;nh1&#034;&gt;1&lt;/a&gt;]&lt;/span&gt;. Mais r&#233;gler de pas en pas risque d'&#234;tre long. On veut donc pouvoir d&#233;cider de combien de pas la but&#233;e est augment&#233;e ou diminu&#233;e lors d'une pression sur un des poussoirs de r&#233;glage. Voici donc le r&#244;le des 2 boutons suppl&#233;mentaires du clavier de r&#233;glage, ils servent &#224; augmenter et diminuer le nombre de pas de r&#233;glage.&lt;/p&gt;
&lt;p&gt;Par d&#233;faut, lorsqu'on d&#233;signe un servo &#224; r&#233;gler, le nombre de pas sera de 8. Une pression sur le poussoir d'augmentation du pas le multipliera par 2 avec un maximum de 32. Une pression sur le poussoir de diminution du pas le divisera par 2 avec un minimum de 1. Le fait de d&#233;signer un nouveau servo r&#233;initialisera le pas de r&#233;glage &#224; 8.&lt;/p&gt;
&lt;h2 class=&#034;spip&#034;&gt;Modification de la classe &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;DescripteurServo&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;La premi&#232;re modification est &#233;vidente. Auparavant, les but&#233;es &#233;taient d&#233;termin&#233;es globalement pour les 8 servomoteurs. Maintenant que l'on veut r&#233;gler les but&#233;es de chaque servomoteur individuellement, il faut que le &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;DescripteurServo&lt;/code&gt; comporte deux donn&#233;es membres &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;angleMin&lt;/code&gt; et &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;angleMax&lt;/code&gt; comme ceci :&lt;/p&gt;
&lt;div class=&#034;precode&#034;&gt;&lt;pre data-raccourci=&#034;code&#034; data-language=&#034;cpp&#034; class='spip_code spip_code_block language-cpp' dir='ltr' style='text-align:left;'&gt;&lt;code&gt;class DescripteurServo { Servo objetServo; /* Objet issu de la biblioth&#232;que Servo de l'Arduino */ int vitesse; /* La vitesse de d&#233;placement du servomoteur */ int angle; /* L'angle du servo-moteur */ int angleMin; /* Angle minimum du servo */ int angleMax; /* Angle maximum du servo */ int pin; /* La broche sur laquelle il est connect&#233; */ byte etatServo; /* son &#233;tat : SERVO_A_ANGLE_MIN, SERVO_A_ANGLE_MAX SERVO_EN_MOUVEMENT_VERS_ANGLE_MAX ou SERVO_EN_MOUVEMENT_VERS_ANGLE_MIN */ ...&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;On va bien entendu conserver des constantes minimum et maximum absolues afin de limiter le r&#233;glage :&lt;/p&gt;
&lt;div class=&#034;precode&#034;&gt;&lt;pre data-raccourci=&#034;code&#034; data-language=&#034;cpp&#034; class='spip_code spip_code_block language-cpp' dir='ltr' style='text-align:left;'&gt;&lt;code&gt;const int ANGLE_MIN = 1000; const int ANGLE_MAX = 2000;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Ces constantes vont &#234;tre employ&#233;es dans le constructeur de &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;DescripteurServo&lt;/code&gt; pour initialiser les donn&#233;es membres &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;angleMin&lt;/code&gt; et &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;angleMax&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;La fonction de r&#233;glage&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Ensuite, il faut &#233;crire une fonction membre de r&#233;glage. Cette fonction est appel&#233;e de &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;loop()&lt;/code&gt; lorsque le codeur d&#233;signe le servo concern&#233;. Cette fonction doit&lt;/p&gt;
&lt;ul class=&#034;spip&#034; role=&#034;list&#034;&gt;&lt;li&gt; lire un &#233;v&#233;nement sur le clavier de r&#233;glage ;&lt;/li&gt;&lt;li&gt; si l'&#233;v&#233;nement est un changement de pas de r&#233;glage, la variable de pas est multipli&#233;e par 2 ou divis&#233;e par 2 ;&lt;/li&gt;&lt;li&gt; si l'&#233;v&#233;nement est un r&#233;glage :
&lt;ul class=&#034;spip&#034; role=&#034;list&#034;&gt;&lt;li&gt; si l'&#233;tat du servo est SERVO_A_ANGLE_MIN, l'angle minimum est ajust&#233;, la vitesse du servo est mise &#224; 1 ou -1 selon le changement pour que le servo vienne de recaler sur l'angle minimum ;&lt;/li&gt;&lt;li&gt; si l'&#233;tat du servo est SERVO_A_ANGLE_MAX, l'angle maximum est ajust&#233;, la vitesse du servo est mise &#224; 1 ou -1 selon le changement pour que le servo vienne de recaler sur l'angle maximum.&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;Afin de s&#233;parer clairement les diff&#233;rents cas, nous allons utiliser des &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;switch ... case&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&#034;precode&#034;&gt;&lt;pre data-raccourci=&#034;code&#034; data-language=&#034;cpp&#034; class='spip_code spip_code_block language-cpp' dir='ltr' style='text-align:left;'&gt;&lt;code&gt;void regleServo() { int numPoussoir; if (clavierReglage.lireEvenement(&amp;numPoussoir) == EVENEMENT_PRESSE) { switch(numPoussoir) { case 0: /* d&#233;placement de la but&#233;e dans le sens trigo */ switch(etatServo) { case SERVO_A_ANGLE_MIN: if (angleMin &lt; angleMax) angleMin += min(pasDeReglage, angleMax - angleMin); objetServo.attach(pin); vitesse = 1; break; case SERVO_A_ANGLE_MAX: if (angleMax &lt; ANGLE_MAX) angleMax += min(pasDeReglage, ANGLE_MAX - angleMax); objetServo.attach(pin); vitesse = 1; break; } break; case 1: /* d&#233;placement de la but&#233;e dans le sens horaire */ switch(etatServo) { case SERVO_A_ANGLE_MIN: if (angleMin &gt; ANGLE_MIN) angleMin -= min(pasDeReglage, angleMin - ANGLE_MIN); objetServo.attach(pin); vitesse = -1; break; case SERVO_A_ANGLE_MAX: if (angleMax &gt; angleMin) angleMax -= min(pasDeReglage, angleMax - angleMin); objetServo.attach(pin); vitesse = -1; break; } break; case 2: /* diminution du pas de r&#233;glage */ if (pasDeReglage &gt; 1) pasDeReglage /= 2; break; case 3: /* augmentation du pas de r&#233;glage */ if (pasDeReglage &lt; 32) pasDeReglage *= 2; break; } } }&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;La gestion du mouvement&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Le r&#233;glage est un cas particulier, l'angle du servo peut &#234;tre en dehors de la fourchette &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;angleMin&lt;/code&gt; et &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;angleMax&lt;/code&gt;. Or la fonction &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;gereServo()&lt;/code&gt; suppose que l'angle est dans la fourchette. Il ne va donc pas fonctionner correctement pour le r&#233;glage. Il faut donc l'adapter.&lt;/p&gt;
&lt;p&gt;Tout d'abord, il nous faut une variable bool&#233;enne qui va indiquer si un r&#233;glage est en cours ou non. Cette variable sera modifi&#233;e dans loop en fonction de la valeur renvoy&#233;e par &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;lireReglage()&lt;/code&gt;, la fonction qui renvoie l'&#233;tat du codeur.&lt;/p&gt;
&lt;p&gt;Si il n'y a aucun r&#233;glage en cours ou si le servo est dans l'une des &#233;tats SERVO_EN_MOUVEMENT_VERS_ANGLE_MAX ou SERVO_EN_MOUVEMENT_ VERS_ANGLE_MIN, il s'agit d'un mouvement normal du servo et le code existant fonctionne. Dans l'autre cas, il faut un code sp&#233;cifique pour g&#233;rer le mouvement vers la nouvelle but&#233;e. Selon la but&#233;e o&#249; le servo est et selon le signe de la vitesse, on d&#233;termine quand le mouvement doit &#234;tre arr&#234;t&#233; :&lt;/p&gt;
&lt;div class=&#034;precode&#034;&gt;&lt;pre data-raccourci=&#034;code&#034; data-language=&#034;cpp&#034; class='spip_code spip_code_block language-cpp' dir='ltr' style='text-align:left;'&gt;&lt;code&gt;if (etatServo == SERVO_A_ANGLE_MIN) { if (vitesse &gt; 0 &amp;&amp; angle &gt;= angleMin) { angle = angleMin; vitesse = 0; objetServo.detach(); } else if (vitesse &lt; 0 &amp;&amp; angle &lt;= angleMin) { angle = angleMin; vitesse = 0; objetServo.detach(); } } else if (etatServo == SERVO_A_ANGLE_MAX) { if (vitesse &gt; 0 &amp;&amp; angle &gt;= angleMax) { angle = angleMax; vitesse = 0; objetServo.detach(); } else if (vitesse &lt; 0 &amp;&amp; angle &lt;= angleMax) { angle = angleMax; vitesse = 0; objetServo.detach(); } }&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Le fait de tester l'angle par rapport aux angles minimum et maximum avec des &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;&gt;=&lt;/code&gt; et &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;&lt;=&lt;/code&gt; est une s&#233;curit&#233;. En effet, en testant avec une &#233;galit&#233; &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;==&lt;/code&gt; et si pour une raison ind&#233;termin&#233;e l'angle d&#233;passait l'angle min ou max, le servo continuerait sont mouvement et irait en but&#233;e m&#233;canique, ce qui pourrait l'endommager.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Modification de &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;loop()&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;loop()&lt;/code&gt; est modifi&#233; pour prendre en compte la fonction de r&#233;glage.&lt;/p&gt;
&lt;div class=&#034;precode&#034;&gt;&lt;pre data-raccourci=&#034;code&#034; data-language=&#034;cpp&#034; class='spip_code spip_code_block language-cpp' dir='ltr' style='text-align:left;'&gt;&lt;code&gt;void loop() { int numServo; /* gestion du mouvement des servos */ for (numServo = 0; numServo &lt; 8; numServo++) servoMoteur[numServo].gereServo(); /* lecture d'un ordre de mouvement */ byte evenement = clavierOrdreServo.lireEvenement(&amp;numServo); /* ex&#233;cution de l'ordre de mouvement */ if (evenement == EVENEMENT_PRESSE) servoMoteur[numServo].evenementServo(); /* lecture du codeur qui d&#233;signe le servo &#224; r&#233;gler */ int servoARegler = lireReglage(); /* si positif ou nul, il y a un servo &#224; r&#233;gler */ reglageEnCours = (servoARegler &gt;= 0); /* si on a chang&#233; de servo &#224; r&#233;gler, le pas est remis &#224; 8 */ if (servoARegler != ancienServoARegler) { ancienServoARegler = servoARegler; pasDeReglage = 8; } /* ex&#233;cution de r&#233;glage */ if (reglageEnCours) servoMoteur[servoARegler].regleServo(); delay(5); }&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Voici le code complet du sketch &#224; t&#233;l&#233;charger.&lt;/p&gt;
&lt;div class='spip_document_328 spip_document spip_documents spip_document_file spip_document_avec_legende' data-legende-len=&#034;57&#034; data-legende-lenx=&#034;x&#034;
&gt;
&lt;figure class=&#034;spip_doc_inner&#034;&gt;
&lt;a href='https://modelleisenbahn.triskell.org/IMG/zip/Huit_boutons_huit_servos_detach_reglage_cpp-3.zip' class=&#034; spip_doc_lien&#034; title='Zip - 3.1 kio' type=&#034;application/zip&#034;&gt;&lt;img src='https://modelleisenbahn.triskell.org/local/cache-vignettes/L64xH64/zip-f045b.svg?1772799586' width='64' height='64' alt='' /&gt;&lt;/a&gt;
&lt;figcaption class='spip_doc_legende'&gt; &lt;div class='spip_doc_titre crayon document-titre-328 '&gt;&lt;strong&gt;Sketch Arduino de l'application avec r&#233;glage des but&#233;es
&lt;/strong&gt;&lt;/div&gt; &lt;/figcaption&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;p&gt;Et une vid&#233;o de la mise en &#339;uvre.&lt;/p&gt;
&lt;div class=&#034;spip_document_330 spip_document spip_documents spip_document_video spip_document_avec_legende&#034; data-legende-len=&#034;50&#034; data-legende-lenx=&#034;x&#034;
&gt;
&lt;figure class=&#034;spip_doc_inner&#034;&gt;
&lt;div class=&#034;video-intrinsic-wrapper&#034; style='height:0;width:640px;max-width:100%;padding-bottom:56.25%;position:relative;'&gt; &lt;div class=&#034;video-wrapper&#034; style=&#034;position: absolute;top:0;left:0;width:100%;height:100%;&#034;&gt; &lt;video class=&#034;mejs mejs-330&#034; data-id=&#034;719d7d6751e6f1f74f9768f9841bd654&#034; data-mejsoptions='{&#034;iconSprite&#034;: &#034;plugins-dist/medias/lib/mejs/mejs-controls.svg&#034;,&#034;alwaysShowControls&#034;: true,&#034;pluginPath&#034;:&#034;plugins-dist/medias/lib/mejs/&#034;,&#034;loop&#034;:false,&#034;videoWidth&#034;:&#034;100%&#034;,&#034;videoHeight&#034;:&#034;100%&#034;}' width=&#034;100%&#034; height=&#034;100%&#034; controls=&#034;controls&#034; preload=&#034;none&#034; &gt; &lt;source type=&#034;application/x-shockwave-flash&#034; src=&#034;http://www.youtube.com/v/rc7IQZXfZqM?version=3&amp;hl=fr_FR&amp;rel=0&#034; /&gt; &lt;img src='https://modelleisenbahn.triskell.org/local/cache-vignettes/L64xH64/swf-d2c4d-75a7b.svg?1772798901' width='64' height='64' alt='Impossible de lire la video' /&gt; &lt;/video&gt; &lt;/div&gt;
&lt;/div&gt;
&lt;figcaption class='spip_doc_legende'&gt; &lt;div class='spip_doc_titre crayon document-titre-330 '&gt;&lt;strong&gt;Test de l'application avec le r&#233;glage des but&#233;es
&lt;/strong&gt;&lt;/div&gt; &lt;/figcaption&gt;
&lt;div class=&#034;base64javascript95743841069cf6312f310b7.50465382&#034; title=&#034;PHNjcmlwdD4gdmFyIG1lanNwYXRoPSdwbHVnaW5zLWRpc3QvbWVkaWFzL2xpYi9tZWpzL21lZGlhZWxlbWVudC1hbmQtcGxheWVyLm1pbi5qcz8xNzcyNzk1ODQwJyxtZWpzY3NzPSdwbHVnaW5zLWRpc3QvbWVkaWFzL2xpYi9tZWpzL21lZGlhZWxlbWVudHBsYXllci5taW4uY3NzPzE3NzI3OTU4NDAnOwp2YXIgbWVqc2xvYWRlcjsKKGZ1bmN0aW9uKCl7dmFyIGE9bWVqc2xvYWRlcjsidW5kZWZpbmVkIj09dHlwZW9mIGEmJihtZWpzbG9hZGVyPWE9e2dzOm51bGwscGx1Zzp7fSxjc3M6e30saW5pdDpudWxsLGM6MCxjc3Nsb2FkOm51bGx9KTthLmluaXR8fChhLmNzc2xvYWQ9ZnVuY3Rpb24oYyl7aWYoInVuZGVmaW5lZCI9PXR5cGVvZiBhLmNzc1tjXSl7YS5jc3NbY109ITA7dmFyIGI9ZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgibGluayIpO2IuaHJlZj1jO2IucmVsPSJzdHlsZXNoZWV0IjtiLnR5cGU9InRleHQvY3NzIjtkb2N1bWVudC5nZXRFbGVtZW50c0J5VGFnTmFtZSgiaGVhZCIpWzBdLmFwcGVuZENoaWxkKGIpfX0sYS5pbml0PWZ1bmN0aW9uKCl7ITA9PT1hLmdzJiZmdW5jdGlvbihjKXtqUXVlcnkoImF1ZGlvLm1lanMsdmlkZW8ubWVqcyIpLm5vdCgiLmRvbmUsLm1lanNfX3BsYXllciIpLmVhY2goZnVuY3Rpb24oKXtmdW5jdGlvbiBiKCl7dmFyIGU9ITAsaDtmb3IoaCBpbiBkLmNzcylhLmNzc2xvYWQoZC5jc3NbaF0pO2Zvcih2YXIgZiBpbiBkLnBsdWdpbnMpInVuZGVmaW5lZCI9PQp0eXBlb2YgYS5wbHVnW2ZdPyhlPSExLGEucGx1Z1tmXT0hMSxqUXVlcnkuZ2V0U2NyaXB0KGQucGx1Z2luc1tmXSxmdW5jdGlvbigpe2EucGx1Z1tmXT0hMDtiKCl9KSk6MD09YS5wbHVnW2ZdJiYoZT0hMSk7ZSYmalF1ZXJ5KCIjIitjKS5tZWRpYWVsZW1lbnRwbGF5ZXIoalF1ZXJ5LmV4dGVuZChkLm9wdGlvbnMse3N1Y2Nlc3M6ZnVuY3Rpb24oYSxjKXtmdW5jdGlvbiBiKCl7dmFyIGI9alF1ZXJ5KGEpLmNsb3Nlc3QoIi5tZWpzX19pbm5lciIpO2EucGF1c2VkPyhiLmFkZENsYXNzKCJwYXVzaW5nIiksc2V0VGltZW91dChmdW5jdGlvbigpe2IuZmlsdGVyKCIucGF1c2luZyIpLnJlbW92ZUNsYXNzKCJwbGF5aW5nIikucmVtb3ZlQ2xhc3MoInBhdXNpbmciKS5hZGRDbGFzcygicGF1c2VkIil9LDEwMCkpOmIucmVtb3ZlQ2xhc3MoInBhdXNlZCIpLnJlbW92ZUNsYXNzKCJwYXVzaW5nIikuYWRkQ2xhc3MoInBsYXlpbmciKX1iKCk7YS5hZGRFdmVudExpc3RlbmVyKCJwbGF5IixiLCExKTsKYS5hZGRFdmVudExpc3RlbmVyKCJwbGF5aW5nIixiLCExKTthLmFkZEV2ZW50TGlzdGVuZXIoInBhdXNlIixiLCExKTthLmFkZEV2ZW50TGlzdGVuZXIoInBhdXNlZCIsYiwhMSk7Zy5hdHRyKCJhdXRvcGxheSIpJiZhLnBsYXkoKX19KSl9dmFyIGc9alF1ZXJ5KHRoaXMpLmFkZENsYXNzKCJkb25lIiksYzsoYz1nLmF0dHIoImlkIikpfHwoYz0ibWVqcy0iK2cuYXR0cigiZGF0YS1pZCIpKyItIithLmMrKyxnLmF0dHIoImlkIixjKSk7dmFyIGQ9e29wdGlvbnM6e30scGx1Z2luczp7fSxjc3M6W119LGUsaDtmb3IoZSBpbiBkKWlmKGg9Zy5hdHRyKCJkYXRhLW1lanMiK2UpKWRbZV09alF1ZXJ5LnBhcnNlSlNPTihoKTtiKCl9KX0oalF1ZXJ5KX0pO2EuZ3N8fCgidW5kZWZpbmVkIiE9PXR5cGVvZiBtZWpzY3NzJiZhLmNzc2xvYWQobWVqc2NzcyksYS5ncz1qUXVlcnkuZ2V0U2NyaXB0KG1lanNwYXRoLGZ1bmN0aW9uKCl7YS5ncz0hMDthLmluaXQoKTtqUXVlcnkoYS5pbml0KTtvbkFqYXhMb2FkKGEuaW5pdCl9KSl9KSgpOzwvc2NyaXB0Pg==&#034;&gt;&lt;/div&gt; &lt;/figure&gt;
&lt;/div&gt;
&lt;p&gt;Comme expliqu&#233; dans la vid&#233;o, il reste une paire de d&#233;tails &#224; r&#233;gler. Nous verrons cela dans le prochain article mais on commence &#224; voir le bout du tunnel !&lt;/p&gt;&lt;/div&gt;
		&lt;hr /&gt;
		&lt;div class='rss_notes'&gt;&lt;div id=&#034;nb1&#034;&gt;
&lt;p&gt;&lt;span class=&#034;spip_note_ref&#034;&gt;[&lt;a href=&#034;#nh1&#034; class=&#034;spip_note&#034; title=&#034;Notes 1&#034; rev=&#034;appendix&#034;&gt;1&lt;/a&gt;] &lt;/span&gt;Un pas vaut 1&#181;s puisqu'on utilise la fonction &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;writeMicroseconds(...)&lt;/code&gt; pour piloter les servos&lt;/p&gt;
&lt;/div&gt;&lt;/div&gt;
		
		</content:encoded>


		

	</item>
<item xml:lang="fr">
		<title>Clavier de r&#233;glage des but&#233;es</title>
		<link>https://modelleisenbahn.triskell.org/spip.php?article62</link>
		<guid isPermaLink="true">https://modelleisenbahn.triskell.org/spip.php?article62</guid>
		<dc:date>2013-11-30T12:49:01Z</dc:date>
		<dc:format>text/html</dc:format>
		<dc:language>fr</dc:language>
		<dc:creator>Jean-Luc</dc:creator>


		<dc:subject>aiguille</dc:subject>
		<dc:subject>servo</dc:subject>
		<dc:subject>Arduino</dc:subject>

		<description>
&lt;p&gt;Essayant de ne pas faire de trop gros articles indigestes, je saucissonne un peu plus les sujets. Voici le 2e sur le r&#233;glage des but&#233;es. Il porte sur la transformation du programme que nous avions &#233;crit pour le clavier analogique afin que le m&#234;me programme puisse servir pour le clavier de r&#233;glage et en fait pour n'importe quel clavier analogique. En informatique on appelle &#231;a la g&#233;n&#233;ricit&#233;. Poussoirs de r&#233;glage de la position &lt;br class='autobr' /&gt;
Les poussoirs de r&#233;glage de la position sont mis en &#339;uvre avec (&#8230;)&lt;/p&gt;


-
&lt;a href="https://modelleisenbahn.triskell.org/spip.php?rubrique22" rel="directory"&gt;Man&#339;uvre des aiguilles avec des servo-moteurs&lt;/a&gt;

/ 
&lt;a href="https://modelleisenbahn.triskell.org/spip.php?mot4" rel="tag"&gt;aiguille&lt;/a&gt;, 
&lt;a href="https://modelleisenbahn.triskell.org/spip.php?mot5" rel="tag"&gt;servo&lt;/a&gt;, 
&lt;a href="https://modelleisenbahn.triskell.org/spip.php?mot10" rel="tag"&gt;Arduino&lt;/a&gt;

		</description>


 <content:encoded>&lt;div class='rss_texte'&gt;&lt;p&gt;Essayant de ne pas faire de trop gros articles indigestes, je saucissonne un peu plus les sujets. Voici le 2&lt;sup&gt;e&lt;/sup&gt; sur le r&#233;glage des but&#233;es. Il porte sur la transformation du &lt;a href='https://modelleisenbahn.triskell.org/spip.php?article59' class=&#034;spip_in&#034;&gt;programme que nous avions &#233;crit pour le clavier analogique&lt;/a&gt; afin que le m&#234;me programme puisse servir pour le clavier de r&#233;glage et en fait pour n'importe quel clavier analogique. En informatique on appelle &#231;a la g&#233;n&#233;ricit&#233;.&lt;/p&gt;
&lt;h2 class=&#034;spip&#034;&gt;Poussoirs de r&#233;glage de la position&lt;/h2&gt;
&lt;p&gt;Les poussoirs de r&#233;glage de la position sont mis en &#339;uvre avec un clavier analogique de la m&#234;me mani&#232;re que les poussoirs de commande mais nous allons employer 4 poussoirs au lieu de 8 et les connecter sur l'entr&#233;e analogique A1. Nous allons voir plus tard pourquoi 4 et pas 2.&lt;/p&gt;
&lt;p&gt;Pour avoir les valeurs des r&#233;sistances, il suffit de faire sauter un poussoir sur deux dans le tableau de &#171; &lt;a href='https://modelleisenbahn.triskell.org/spip.php?article59' class=&#034;spip_in&#034;&gt;Plusieurs boutons poussoir sur une entr&#233;e analogique&lt;/a&gt; &#187; et d'additionner les deux r&#233;sistances de part et d'autre des poussoirs supprim&#233;s. Les valeurs des r&#233;sistances peuvent &#234;tre moins pr&#233;cises car les plages de valeurs sont deux fois plus larges. Nous avons donc :&lt;/p&gt;
&lt;table class=&#034;table spip&#034;&gt;
&lt;tbody&gt;
&lt;tr class='row_odd odd'&gt;
&lt;td&gt; &lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Tension&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;R&#233;sistance&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;R&#233;sistance approch&#233;e&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Tension approch&#233;e&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Erreur&lt;/strong&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr class='row_even even'&gt;
&lt;td&gt;R1&lt;/td&gt;
&lt;td&gt;1,25V&lt;/td&gt;
&lt;td&gt;110&#937;&lt;/td&gt;
&lt;td&gt;120&#937;&lt;/td&gt;
&lt;td&gt;1,33V&lt;/td&gt;
&lt;td&gt;6,4%&lt;/td&gt;&lt;/tr&gt;
&lt;tr class='row_odd odd'&gt;
&lt;td&gt;R2&lt;/td&gt;
&lt;td&gt;2,5V&lt;/td&gt;
&lt;td&gt;212&#937;&lt;/td&gt;
&lt;td&gt;220&#937;&lt;/td&gt;
&lt;td&gt;2,61V&lt;/td&gt;
&lt;td&gt;4,4%&lt;/td&gt;&lt;/tr&gt;
&lt;tr class='row_even even'&gt;
&lt;td&gt;R3&lt;/td&gt;
&lt;td&gt;3,75V&lt;/td&gt;
&lt;td&gt;650&#937;&lt;/td&gt;
&lt;td&gt;560&#937;&lt;/td&gt;
&lt;td&gt;3,65V&lt;/td&gt;
&lt;td&gt;1,78%&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;h2 class=&#034;spip&#034;&gt;Le logiciel&lt;/h2&gt;
&lt;p&gt;Nous avons maintenant deux clavier analogiques, l'un pour les 8 poussoirs de changement de positions des servomoteurs et l'autre avec 4 pour le r&#233;glage. Nous allons bien entendu utiliser les m&#234;mes fonctions pour les deux claviers et en profiter pour les passer en C++ &lt;a href='https://modelleisenbahn.triskell.org/spip.php?article63' class=&#034;spip_in&#034;&gt;comme nous l'avons fait pour les servomoteurs&lt;/a&gt; car maintenant que nous avons 2 claviers, il est logique d'avoir des objets. Un clavier analogique est jusqu'&#224; pr&#233;sent repr&#233;sent&#233; par 2 variables.&lt;/p&gt;
&lt;div class=&#034;precode&#034;&gt;&lt;pre data-raccourci=&#034;code&#034; data-language=&#034;C&#034; class='spip_code spip_code_block language-C' dir='ltr' style='text-align:left;'&gt;&lt;code&gt;byte etatAutomate = NON_PRESSE; int etatPoussoir = -1;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Mais les fonctions &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;lirePoussoirs()&lt;/code&gt; et &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;lireEvenement()&lt;/code&gt; que nous avons &#233;crites ont en dur dans le code le fait qu'il y ait 8 poussoirs. Il en est de m&#234;me pour la broche de connexion. Par cons&#233;quent, pour que les fonctions puissent &#234;tre g&#233;n&#233;riques, nous allons en plus avoir besoin de la broche de connexion, du nombre de poussoirs et de ce nombre de poussoirs, nous allons d&#233;duire la taille d'une plage de valeurs. Voici le d&#233;but de notre classe &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;DescripteurClavierAnalogique&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&#034;precode&#034;&gt;&lt;pre data-raccourci=&#034;code&#034; data-language=&#034;cpp&#034; class='spip_code spip_code_block language-cpp' dir='ltr' style='text-align:left;'&gt;&lt;code&gt;class DescripteurClavierAnalogique { byte etatAutomate; int etatPoussoir; int taillePlage; int nbPoussoirs; int pin; };&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Nous allons ajouter le constructeur qui contient les initialisations ind&#233;pendantes du nombre de poussoirs et de la broche et une fonction de connexion qui va contenir les initialisations qui en sont d&#233;pendantes.&lt;/p&gt;
&lt;div class=&#034;precode&#034;&gt;&lt;pre data-raccourci=&#034;code&#034; data-language=&#034;cpp&#034; class='spip_code spip_code_block language-cpp' dir='ltr' style='text-align:left;'&gt;&lt;code&gt; public: DescripteurClavierAnalogique() { etatAutomate = NON_PRESSE; etatPoussoir = -1; } void connecte(int pinDeConnexion, int nombreDePoussoirs) { pin = pinDeConnexion; nbPoussoirs = nombreDePoussoirs; /* * calcule la taille d'une plage * le convertisseur a 1024 valeurs, Le taille de plage * est &#233;gal &#224; 1024/nombreDePoussoirs. */ taillePlage = 1024 / nombreDePoussoirs; }&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Enfin, nous allons modifier &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;lirePoussoirs()&lt;/code&gt; afin de remplacer les valeur en dur par la plage de valeurs ou le nombre de poussoirs. &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;lirePoussoirs()&lt;/code&gt; est plac&#233; dans la partie priv&#233;e de la classe car il n'est appel&#233; que part la fonction &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;lireEvenement()&lt;/code&gt;&lt;/p&gt;
&lt;div class=&#034;precode&#034;&gt;&lt;pre data-raccourci=&#034;code&#034; data-language=&#034;cpp&#034; class='spip_code spip_code_block language-cpp' dir='ltr' style='text-align:left;'&gt;&lt;code&gt; int lirePoussoirs() { int resultat; int numPoussoir = (analogRead(pin) + taillePlage / 2) /taillePlage; int nouvelEtatPoussoir = etatPoussoir; /* &#224; priori rien ne change */ switch (etatAutomate) { case NON_PRESSE: if (numPoussoir &lt; nbPoussoirs) etatAutomate = ENFONCE; break; case ENFONCE: if (numPoussoir &lt; nbPoussoirs) { etatAutomate = PRESSE; nouvelEtatPoussoir = numPoussoir; } else { etatAutomate = NON_PRESSE; } break; case PRESSE: if (numPoussoir == nbPoussoirs) { etatAutomate = NON_PRESSE; nouvelEtatPoussoir = -1; } break; } return nouvelEtatPoussoir; }&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Nous pouvons maintenant cr&#233;er nos deux objets &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;clavierOrdreServo&lt;/code&gt; et &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;clavierReglage&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&#034;precode&#034;&gt;&lt;pre data-raccourci=&#034;code&#034; data-language=&#034;cpp&#034; class='spip_code spip_code_block language-cpp' dir='ltr' style='text-align:left;'&gt;&lt;code&gt;DescripteurClavierAnalogique clavierOrdreServo; DescripteurClavierAnalogique clavierReglage;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;et &#224; appeler la fonction &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;connect(...)&lt;/code&gt; dans &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;setup()&lt;/code&gt;&lt;/p&gt;
&lt;div class=&#034;precode&#034;&gt;&lt;pre data-raccourci=&#034;code&#034; data-language=&#034;cpp&#034; class='spip_code spip_code_block language-cpp' dir='ltr' style='text-align:left;'&gt;&lt;code&gt; clavierOrdreServo.connecte(0,8); /* pin A0, 8 poussoirs */ clavierReglage.connecte(1,4); /* pin A1, 4 poussoirs */&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Pour finir, la classe compl&#232;te de gestion de clavier analogique avec l'ajout de &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;lireEvenement(...)&lt;/code&gt;. Cette classe est r&#233;utilisable sans modification dans n'importe quel montage comportant un clavier analogique.&lt;/p&gt;
&lt;div class=&#034;precode&#034;&gt;&lt;pre data-raccourci=&#034;code&#034; data-language=&#034;cpp&#034; class='spip_code spip_code_block language-cpp' dir='ltr' style='text-align:left;'&gt;&lt;code&gt;class DescripteurClavierAnalogique { byte etatAutomate; int etatPoussoir; int taillePlage; int nbPoussoirs; int pin; int lirePoussoirs() { int resultat; int numPoussoir = (analogRead(pin) + taillePlage / 2) /taillePlage; int nouvelEtatPoussoir = etatPoussoir; /* &#224; priori rien ne change */ switch (etatAutomate) { case NON_PRESSE: if (numPoussoir &lt; nbPoussoirs) etatAutomate = ENFONCE; break; case ENFONCE: if (numPoussoir &lt; nbPoussoirs) { etatAutomate = PRESSE; nouvelEtatPoussoir = numPoussoir; } else { etatAutomate = NON_PRESSE; } break; case PRESSE: if (numPoussoir == nbPoussoirs) { etatAutomate = NON_PRESSE; nouvelEtatPoussoir = -1; } break; } return nouvelEtatPoussoir; } public: DescripteurClavierAnalogique() { etatAutomate = NON_PRESSE; etatPoussoir = -1; } void connecte(int pinDeConnexion, int nombreDePoussoirs) { pin = pinDeConnexion; nbPoussoirs = nombreDePoussoirs; /* * calcule la taille d'une plage * le convertisseur a 1024 valeurs, Le taille de plage * est &#233;gal &#224; 1024/nombreDePoussoirs. Le d&#233;calage est * la taille de la plage sur 2 */ taillePlage = 1024 / nombreDePoussoirs; } /* * construction d'un &#233;v&#233;nement en comparant * le nouvel &#233;tat des poussoirs avec l'&#233;tat pr&#233;c&#233;dent. */ byte lireEvenement(int *numPoussoir) { byte evenement; int nouvelEtatPoussoir = lirePoussoirs(); if (nouvelEtatPoussoir == etatPoussoir) evenement = AUCUN_EVENEMENT; if (nouvelEtatPoussoir &gt;= 0 &amp;&amp; etatPoussoir == -1) evenement = EVENEMENT_PRESSE; if (nouvelEtatPoussoir == -1 &amp;&amp; etatPoussoir &gt;= 0) evenement = EVENEMENT_RELACHE; etatPoussoir = nouvelEtatPoussoir; *numPoussoir = etatPoussoir; return evenement; } };&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Maintenant que les deux commandes n&#233;cessaires au r&#233;glage sont mises en place, nous allons pouvoir nous concentrer sur le r&#233;glage en lui-m&#234;me.&lt;/p&gt;&lt;/div&gt;
		
		</content:encoded>


		

	</item>
<item xml:lang="fr">
		<title>S&#233;lection d'un servomoteur pour le r&#233;glage des but&#233;es</title>
		<link>https://modelleisenbahn.triskell.org/spip.php?article61</link>
		<guid isPermaLink="true">https://modelleisenbahn.triskell.org/spip.php?article61</guid>
		<dc:date>2013-11-23T16:06:22Z</dc:date>
		<dc:format>text/html</dc:format>
		<dc:language>fr</dc:language>
		<dc:creator>Jean-Luc</dc:creator>


		<dc:subject>aiguille</dc:subject>
		<dc:subject>servo</dc:subject>
		<dc:subject>Arduino</dc:subject>

		<description>
&lt;p&gt;Le r&#233;glage des but&#233;es est un point important. En effet, chaque servo moteur va avoir un neutre un peu diff&#233;rent de ses cong&#233;n&#232;res. Il en va de m&#234;me pour les positions extr&#234;mes. De plus, chaque installation d'aiguille est un peu diff&#233;rente des autres. &lt;br class='autobr' /&gt;
Il est donc essentiel de pouvoir, servomoteur par servomoteur, r&#233;gler les deux positions extr&#234;mes. &lt;br class='autobr' /&gt;
Le mat&#233;riel &lt;br class='autobr' /&gt;
Afin de s&#233;lectionner l'un des servomoteurs pour r&#233;gler, au moyen de deux poussoirs, sa position extr&#234;me actuelle nous avons (&#8230;)&lt;/p&gt;


-
&lt;a href="https://modelleisenbahn.triskell.org/spip.php?rubrique22" rel="directory"&gt;Man&#339;uvre des aiguilles avec des servo-moteurs&lt;/a&gt;

/ 
&lt;a href="https://modelleisenbahn.triskell.org/spip.php?mot4" rel="tag"&gt;aiguille&lt;/a&gt;, 
&lt;a href="https://modelleisenbahn.triskell.org/spip.php?mot5" rel="tag"&gt;servo&lt;/a&gt;, 
&lt;a href="https://modelleisenbahn.triskell.org/spip.php?mot10" rel="tag"&gt;Arduino&lt;/a&gt;

		</description>


 <content:encoded>&lt;div class='rss_texte'&gt;&lt;p&gt;Le r&#233;glage des but&#233;es est un point important. En effet, chaque servo moteur va avoir un neutre un peu diff&#233;rent de ses cong&#233;n&#232;res. Il en va de m&#234;me pour les positions extr&#234;mes. De plus, chaque installation d'aiguille est un peu diff&#233;rente des autres.&lt;/p&gt;
&lt;p&gt;Il est donc essentiel de pouvoir, servomoteur par servomoteur, r&#233;gler les deux positions extr&#234;mes.&lt;/p&gt;
&lt;h2 class=&#034;spip&#034;&gt;Le mat&#233;riel&lt;/h2&gt;
&lt;p&gt;Afin de s&#233;lectionner l'un des servomoteurs pour r&#233;gler, au moyen de deux poussoirs, sa position extr&#234;me actuelle nous avons besoin d'un dispositif permettant de donner un num&#233;ro de servomoteur. Le dispositif le plus adapt&#233; est un codeur rotatif &#224; 10 positions comme celui-ci.&lt;/p&gt;
&lt;div class='spip_document_271 spip_document spip_documents spip_document_image spip_documents_center spip_document_center spip_document_avec_legende' data-legende-len=&#034;40&#034; data-legende-lenx=&#034;x&#034;
&gt;
&lt;figure class=&#034;spip_doc_inner&#034;&gt; &lt;img src='https://modelleisenbahn.triskell.org/local/cache-vignettes/L500xH375/P-02274jpg-88850-655e4.jpg?1692224382' width='500' height='375' alt='' /&gt;
&lt;figcaption class='spip_doc_legende'&gt; &lt;div class='spip_doc_descriptif crayon document-descriptif-271 '&gt;&lt;a href=&#034;http://akizukidenshi.com/img/goods/2/P-02274.jpg&#034; class=&#034;spip_url spip_out&#034; rel=&#034;external&#034;&gt;http://akizukidenshi.com/img/goods/...&lt;/a&gt;
&lt;/div&gt; &lt;/figcaption&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;p&gt;Ces codeurs rotatifs ont 6 broches. 2 d'entre-elles sont reli&#233;es entre elles et communes, les 4 autres codent en binaire la position du bouton (4 bits).&lt;/p&gt;
&lt;p&gt;Comme 5 entr&#233;es analogiques sont disponibles et qu'il est aussi possible de les utiliser comme entr&#233;e num&#233;rique, on ne va pas finasser et simplement utiliser une entr&#233;e par bit&lt;span class=&#034;spip_note_ref&#034;&gt; [&lt;a href=&#034;#nb1&#034; class=&#034;spip_note&#034; rel=&#034;appendix&#034; title=&#034;On rappelle que les entr&#233;es/sorties logiques, en haut de l'Arduino, encore (&#8230;)&#034; id=&#034;nh1&#034;&gt;1&lt;/a&gt;]&lt;/span&gt;. 1 entr&#233;e analogique, A1, restera disponible pour les poussoirs de r&#233;glage.&lt;/p&gt;
&lt;p&gt;Je n'ai pas de codeur rotatif en stock, &#224; la place je vais utiliser un DIP-switch &#224; 4 interrupteurs sur lequel le num&#233;ro du servo sera cod&#233; en binaire et qui sera raccord&#233; exactement de la m&#234;me fa&#231;on que le codeur. Par convention, on d&#233;cide que la valeur 0 (position 0 du codeur) est le mode d'exploitation. Aucun servo n'est s&#233;lectionn&#233; par le codeur. Les valeurs de 1 &#224; 8 permettent de s&#233;lectionner le servo &#224; r&#233;gler. La valeur 9 correspond aussi au mode exploitation o&#249; aucun servo n'est s&#233;lectionn&#233;.&lt;/p&gt;
&lt;p&gt;Le codeur est donc raccord&#233; de la mani&#232;re suivante aux entr&#233;es A2 &#224; A5.&lt;/p&gt;
&lt;div class='spip_document_321 spip_document spip_documents spip_document_image spip_documents_center spip_document_center spip_document_avec_legende' data-legende-len=&#034;373&#034; data-legende-lenx=&#034;xxxx&#034;
&gt;
&lt;figure class=&#034;spip_doc_inner&#034;&gt; &lt;img src='https://modelleisenbahn.triskell.org/local/cache-vignettes/L486xH543/codeur-b7f3c.png?1692224286' width='486' height='543' alt='' /&gt;
&lt;figcaption class='spip_doc_legende'&gt; &lt;div class='spip_doc_titre crayon document-titre-321 '&gt;&lt;strong&gt;C&#226;blage du codeur
&lt;/strong&gt;&lt;/div&gt; &lt;div class='spip_doc_descriptif crayon document-descriptif-321 '&gt;Les interrupteurs c3, c2, c1 et c0 repr&#233;sentent chacun un chiffre binaire. Par convention, un 0 correspond &#224; l'interrupteur ouvert et un 1 &#224; l'interrupteur ferm&#233;. Si tous les interrupteurs sont ouverts, la valeur 0 est cod&#233;e, si c0 est ferm&#233; et les autres ouverts la valeur 1 est cod&#233;e. Si c2 et c1 sont ferm&#233;s, les autres ouverts la valeur 6 est cod&#233;e.
&lt;/div&gt; &lt;/figcaption&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;p&gt;Les entr&#233;es dispose de r&#233;sistances de tirage &#224; 5V (on dit pull-up) interne que l'on peut activer par programme. Quand les interrupteurs sont ouverts, c'est &#224; dire &#224; 0 par convention, la valeur pr&#233;sente sur les entr&#233;es est 5V et non 0V ; Il faut en tenir compte pour construire le logiciel.&lt;/p&gt;
&lt;h2 class=&#034;spip&#034;&gt;Le logiciel&lt;/h2&gt;
&lt;p&gt;Pour lire la valeur num&#233;rique cod&#233;e et la stocker dans une variable enti&#232;re &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;servoARegler&lt;/code&gt;, il faut donc lire les entr&#233;es A2, A3, A4 et A5 en num&#233;rique, en d&#233;duire une valeur de bit et positionner le bit correspondant dans &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;servoARegler&lt;/code&gt;. C'est l'occasion de voir une nouvelle sp&#233;cificit&#233; du langage C, la manipulation des bits dans une variable.&lt;/p&gt;
&lt;p&gt;Le langage C permet de faire des op&#233;rations logiques bit &#224; bit. Les op&#233;rateurs permettant de telles op&#233;rations sont : le &lt;i&gt;et&lt;/i&gt; bit &#224; bit, not&#233; &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;&amp;&lt;/code&gt;, le &lt;i&gt;ou&lt;/i&gt; bit &#224; bit, not&#233; &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;|&lt;/code&gt;, le &lt;i&gt;ou exclusif&lt;/i&gt; bit &#224; bit, not&#233; &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;^&lt;/code&gt; et le &lt;i&gt;non&lt;/i&gt; (inversion de bit) bit &#224; bit not&#233; &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;~&lt;/code&gt;. Il existe aussi deux op&#233;rateurs de d&#233;calage : &lt;i&gt;d&#233;calage logique vers la gauche&lt;/i&gt; d'un certain nombre de bits, not&#233; &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;&lt;&lt;&lt;/code&gt; et le &lt;i&gt;d&#233;calage vers la droite&lt;/i&gt; d'un certain nombre de bits, not&#233; &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;&gt;&gt;&lt;/code&gt;. Dans les deux cas, les bits laiss&#233;s libres par le d&#233;calage sont &#224; 0&lt;span class=&#034;spip_note_ref&#034;&gt; [&lt;a href=&#034;#nb2&#034; class=&#034;spip_note&#034; rel=&#034;appendix&#034; title=&#034;Seulement si la variable est non sign&#233;e. Si la variable est sign&#233;e, le (&#8230;)&#034; id=&#034;nh2&#034;&gt;2&lt;/a&gt;]&lt;/span&gt;, les bits qui sont expuls&#233;s sont perdus.&lt;/p&gt;
&lt;p&gt;Ainsi, si l'on veut construire un byte dont tous les bits sont &#224; 0 sauf les bits 0, 2 et 4 qui sont &#224; 1 :&lt;/p&gt;
&lt;div class='spip_document_274 spip_document spip_documents spip_document_image spip_documents_center spip_document_center'&gt;
&lt;figure class=&#034;spip_doc_inner&#034;&gt; &lt;img src='https://modelleisenbahn.triskell.org/local/cache-vignettes/L330xH56/valeur-ef212.png?1692224286' width='330' height='56' alt='' /&gt;
&lt;/figure&gt;
&lt;/div&gt;
&lt;p&gt;On peut &#233;crire : &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;1 &lt;&lt; 4 | 1 &lt;&lt; 2 | 1&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;C'est &#224; dire :&lt;/p&gt;
&lt;div class='spip_document_316 spip_document spip_documents spip_document_image spip_documents_center spip_document_center'&gt;
&lt;figure class=&#034;spip_doc_inner&#034;&gt; &lt;img src='https://modelleisenbahn.triskell.org/local/cache-vignettes/L500xH233/composition-2-617da.png?1692224382' width='500' height='233' alt='' /&gt;
&lt;/figure&gt;
&lt;/div&gt;
&lt;p&gt;Ce qui est bien le r&#233;sultat escompt&#233;.&lt;/p&gt;
&lt;p&gt;On peut se poser la question de savoir que renvoit la lecture d'une entr&#233;e en num&#233;rique par un &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;digitalRead(...)&lt;/code&gt;. Eh bien elle vaut soit HIGH, soit LOW. Ces deux constantes sont en fait des entiers qui valent 1 pour HIGH et 0 pour LOW. On peut donc utiliser la valeur renvoy&#233;e par un &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;digitalRead(...)&lt;/code&gt; dans un calcul. C'est ce que nous allons faire pour calculer la valeur du codeur.&lt;/p&gt;
&lt;p&gt;En examinant le sch&#233;ma de connexion, on voit que la condition permettant de construire le bit correspondant &#224; une des entr&#233;es est l'inverse de la valeur renvoy&#233;e par &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;digitalRead(...)&lt;/code&gt; parce que la position ouverte de l'interrupteur correspond &#224; +5V. Il faut donc inverser cette valeur en utilisant le non logique : &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;!&lt;/code&gt;. Cet op&#233;rateur retourne un 1 si son op&#233;rande est un 0 et un 0 si son op&#233;rande est diff&#233;rent de 0.&lt;/p&gt;
&lt;p&gt;Donc la valeur du codeur peut &#234;tre construite par l'expression suivante :&lt;/p&gt;
&lt;div class=&#034;precode&#034;&gt;&lt;pre data-raccourci=&#034;code&#034; data-language=&#034;C&#034; class='spip_code spip_code_block language-C' dir='ltr' style='text-align:left;'&gt;&lt;code&gt;servoARegler = (! digitalRead(A2)) &lt;&lt; 3 | (! digitalRead(A3)) &lt;&lt; 2 | (! digitalRead(A4)) &lt;&lt; 1 | (! digitalRead(A5));&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Pour programmer proprement, on va loger ceci dans une fonction, &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;lireReglage()&lt;/code&gt; et en profiter pour recadrer la valeur brute. Si la valeur brute est plus grande que 8, elle est remise &#224; 0 et la valeur brute - 1 est retourn&#233;e. De cette mani&#232;re -1 signifie &#171; rien &#224; r&#233;gler &#187; et une valeur positive d&#233;signe le num&#233;ro du servo &#224; r&#233;gler.&lt;/p&gt;
&lt;div class=&#034;precode&#034;&gt;&lt;pre data-raccourci=&#034;code&#034; data-language=&#034;C&#034; class='spip_code spip_code_block language-C' dir='ltr' style='text-align:left;'&gt;&lt;code&gt;/* * Lecture du codeur de r&#233;glage. * Retourne -1 si aucun servo n'est s&#233;lectionn&#233; et * le num&#233;ro du servo de 0 &#224; 7 si un servo est s&#233;lectionn&#233; */ int lireReglage() { int servoARegler = (! digitalRead(A2)) &lt;&lt; 3 | (! digitalRead(A3)) &lt;&lt; 2 | (! digitalRead(A4)) &lt;&lt; 1 | (! digitalRead(A5)); if (servoARegler &gt; 8) servoARegler = 0; return servoARegler - 1; }&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Comme c'est l'&#233;tat du codeur qui nous int&#233;resse et non les &#233;v&#233;nements de changement d'&#233;tat, il n'est pas n&#233;cessaire de se pr&#233;occuper des transitoires et autres rebonds.&lt;/p&gt;
&lt;p&gt;Il va aussi falloir activer les r&#233;sistances interne de pull-up. Faisons ceci dans une fonction qui sera appel&#233;e &#224; partir de &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;setup()&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&#034;precode&#034;&gt;&lt;pre data-raccourci=&#034;code&#034; data-language=&#034;C&#034; class='spip_code spip_code_block language-C' dir='ltr' style='text-align:left;'&gt;&lt;code&gt;void initialiseCodeur() { /* Active le pullup des entr&#233;es A2, A3, A4 et A5 */ digitalWrite(A2,HIGH); digitalWrite(A3,HIGH); digitalWrite(A4,HIGH); digitalWrite(A5,HIGH); }&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
		&lt;hr /&gt;
		&lt;div class='rss_notes'&gt;&lt;div id=&#034;nb1&#034;&gt;
&lt;p&gt;&lt;span class=&#034;spip_note_ref&#034;&gt;[&lt;a href=&#034;#nh1&#034; class=&#034;spip_note&#034; title=&#034;Notes 1&#034; rev=&#034;appendix&#034;&gt;1&lt;/a&gt;] &lt;/span&gt;On rappelle que les entr&#233;es/sorties logiques, en haut de l'Arduino, encore disponibles sont r&#233;serv&#233;es pour les LED t&#233;moin.&lt;/p&gt;
&lt;/div&gt;&lt;div id=&#034;nb2&#034;&gt;
&lt;p&gt;&lt;span class=&#034;spip_note_ref&#034;&gt;[&lt;a href=&#034;#nh2&#034; class=&#034;spip_note&#034; title=&#034;Notes 2&#034; rev=&#034;appendix&#034;&gt;2&lt;/a&gt;] &lt;/span&gt;Seulement si la variable est non sign&#233;e. Si la variable est sign&#233;e, le d&#233;calage &#224; droite remplit les bits laiss&#233;s libres avec le bit de signe.&lt;/p&gt;
&lt;/div&gt;&lt;/div&gt;
		
		</content:encoded>


		

	</item>
<item xml:lang="fr">
		<title>8 poussoirs et 8 servos, enfin !</title>
		<link>https://modelleisenbahn.triskell.org/spip.php?article60</link>
		<guid isPermaLink="true">https://modelleisenbahn.triskell.org/spip.php?article60</guid>
		<dc:date>2013-11-17T13:12:48Z</dc:date>
		<dc:format>text/html</dc:format>
		<dc:language>fr</dc:language>
		<dc:creator>Jean-Luc</dc:creator>


		<dc:subject>aiguille</dc:subject>
		<dc:subject>servo</dc:subject>
		<dc:subject>Arduino</dc:subject>

		<description>
&lt;p&gt;Dans &#171; Commande du servo-moteur par bouton poussoir &#187;, nous avons vu comment commander un servo-moteur avec un poussoir. Dans &#171; Plusieurs boutons poussoir sur une entr&#233;e analogique &#187;, nous avons vu comment connecter 8 poussoirs sur une entr&#233;e analogique et d&#233;tecter lequel est press&#233;. Il reste maintenant &#224; mettre en &#339;uvre les 8 servos. &lt;br class='autobr' /&gt;
Les variables pour manipuler les 8 servos &lt;br class='autobr' /&gt;
Si vous vous rappelez, plusieurs variables &#233;taient employ&#233;es pour notre servo : l'objet de type Servo permettant (&#8230;)&lt;/p&gt;


-
&lt;a href="https://modelleisenbahn.triskell.org/spip.php?rubrique22" rel="directory"&gt;Man&#339;uvre des aiguilles avec des servo-moteurs&lt;/a&gt;

/ 
&lt;a href="https://modelleisenbahn.triskell.org/spip.php?mot4" rel="tag"&gt;aiguille&lt;/a&gt;, 
&lt;a href="https://modelleisenbahn.triskell.org/spip.php?mot5" rel="tag"&gt;servo&lt;/a&gt;, 
&lt;a href="https://modelleisenbahn.triskell.org/spip.php?mot10" rel="tag"&gt;Arduino&lt;/a&gt;

		</description>


 <content:encoded>&lt;div class='rss_texte'&gt;&lt;p&gt;Dans &#171; &lt;a href='https://modelleisenbahn.triskell.org/spip.php?article58' class=&#034;spip_in&#034;&gt;Commande du servo-moteur par bouton poussoir&lt;/a&gt; &#187;, nous avons vu comment commander un servo-moteur avec un poussoir. Dans &#171; &lt;a href='https://modelleisenbahn.triskell.org/spip.php?article59' class=&#034;spip_in&#034;&gt;Plusieurs boutons poussoir sur une entr&#233;e analogique&lt;/a&gt; &#187;, nous avons vu comment connecter 8 poussoirs sur une entr&#233;e analogique et d&#233;tecter lequel est press&#233;. Il reste maintenant &#224; mettre en &#339;uvre les 8 servos.&lt;/p&gt;
&lt;h2 class=&#034;spip&#034;&gt;Les variables pour manipuler les 8 servos&lt;/h2&gt;
&lt;p&gt;Si vous vous rappelez, plusieurs variables &#233;taient employ&#233;es pour notre servo : l'objet de type &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;Servo&lt;/code&gt; permettant de le piloter, son angle, sa vitesse, son &#233;tat. Comme ceci.&lt;/p&gt;
&lt;div class=&#034;precode&#034;&gt;&lt;pre data-raccourci=&#034;code&#034; data-language=&#034;C&#034; class='spip_code spip_code_block language-C' dir='ltr' style='text-align:left;'&gt;&lt;code&gt;Servo monServo; int vitesse = 0; int angle = angleMin; byte etatServo = SERVO_A_ANGLE_MIN;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Si nous avons 8 servos, il va falloir 8 exemplaires de chacune de ces variables. Plut&#244;t que de r&#233;pliquer 8 fois ces d&#233;finitions, ce qui serait fastidieux, nous allons cr&#233;er un tableau avec autant d'&#233;l&#233;ments que de servos. Mais avant de cr&#233;er ce tableau, nous devons &lt;i&gt;mettre ces variables ensemble&lt;/i&gt;. Pour les mettre ensemble, il existe en C les &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;struct&lt;/code&gt; pour structure. Comme ceci.&lt;/p&gt;
&lt;div class=&#034;precode&#034;&gt;&lt;pre data-raccourci=&#034;code&#034; data-language=&#034;C&#034; class='spip_code spip_code_block language-C' dir='ltr' style='text-align:left;'&gt;&lt;code&gt;struct DescripteurServo { Servo objetServo; int vitesse; int angle; byte etatServo; };&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Une struct a un nom, ici DescripteurServo, et des membres, objetServo, vitesse, angle et etatServo. &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;struct DescripteurServo&lt;/code&gt; est en quelques sortes un nouveau type de donn&#233;e, comme int ou byte, et on peut l'utiliser pour cr&#233;er un tableau de 8 &#233;l&#233;ments que nous appelons &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;servoMoteur&lt;/code&gt; comme ceci.&lt;/p&gt;
&lt;p&gt;&lt;code data-raccourci=&#034;code&#034; data-language=&#034;C&#034; class='spip_code spip_code_inline language-C' dir='ltr'&gt;struct DescripteurServo servoMoteur[8];&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;servoMoteur&lt;/code&gt; est le nom de notre tableau, le [8] indique qu'il contient 8 &#233;l&#233;ments et &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;struct DescripteurServo&lt;/code&gt; est le type d'un &#233;l&#233;ment.&lt;/p&gt;
&lt;p&gt;Pour acc&#233;der &#224; un &#233;l&#233;ment du tableau &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;servoMoteur&lt;/code&gt;, il faut indiquer son num&#233;ro, entre 0 et 7 compris. Ainsi, &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;servoMoteur[4]&lt;/code&gt; est le 5e &#233;l&#233;ment&lt;span class=&#034;spip_note_ref&#034;&gt; [&lt;a href=&#034;#nb2-1&#034; class=&#034;spip_note&#034; rel=&#034;appendix&#034; title=&#034;Oui le 5e puisque le premier &#224; le num&#233;ro 0&#034; id=&#034;nh2-1&#034;&gt;1&lt;/a&gt;]&lt;/span&gt; du tableau.&lt;/p&gt;
&lt;p&gt;Enfin, pour acc&#233;der &#224; un membre d'un &#233;l&#233;ment, il faut ajouter un &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;.&lt;/code&gt; et le nom de l'&#233;l&#233;ment. Ainsi, &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;servoMoteur[4].angle&lt;/code&gt; permet d'acc&#233;der &#224; l'angle du 5e servo.&lt;/p&gt;
&lt;h2 class=&#034;spip&#034;&gt;La mise &#224; jour de l'angle des 8 servos&lt;/h2&gt;
&lt;p&gt;Pour un seul servo, le morceau de programme de mise &#224; jour de l'angle &#233;tait le suivant.&lt;/p&gt;
&lt;div class=&#034;precode&#034;&gt;&lt;pre data-raccourci=&#034;code&#034; data-language=&#034;C&#034; class='spip_code spip_code_block language-C' dir='ltr' style='text-align:left;'&gt;&lt;code&gt; /* actualisation de l'angle du servo */ monServo.writeMicroseconds(angle); angle = angle + vitesse; if (angle &gt; angleMax) { angle = angleMax; vitesse = 0; etatServo = SERVO_A_ANGLE_MAX; } else if (angle &lt; angleMin) { angle = angleMin; vitesse = 0; etatServo = SERVO_A_ANGLE_MIN; }&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Comme nous avons maintenant un tableau de variables, il faut le r&#233;&#233;crire. Pour bien s&#233;parer les diff&#233;rentes parties du programme qui commence &#224; grossir, nous allons d&#233;placer ce morceau de programme dans une fonction, appelons la &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;gereServo&lt;/code&gt;. Cette fonction prendra un argument, le num&#233;ro de servo &#224; g&#233;rer. Ce num&#233;ro de servo va servir &#224; acc&#233;der au tableau.&lt;/p&gt;
&lt;div class=&#034;precode&#034;&gt;&lt;pre data-raccourci=&#034;code&#034; data-language=&#034;C&#034; class='spip_code spip_code_block language-C' dir='ltr' style='text-align:left;'&gt;&lt;code&gt;void gereServo(int numServo) { servoMoteur[numServo].objetServo.writeMicroseconds( servoMoteur[numServo].angle); servoMoteur[numServo].angle += servoMoteur[numServo].vitesse; if (servoMoteur[numServo].angle &gt; angleMax) { servoMoteur[numServo].angle = angleMax; servoMoteur[numServo].vitesse = 0; servoMoteur[numServo].etatServo = SERVO_A_ANGLE_MAX; } else if (servoMoteur[numServo].angle &lt; angleMin) { servoMoteur[numServo].angle = angleMin; servoMoteur[numServo].vitesse = 0; servoMoteur[numServo].etatServo = SERVO_A_ANGLE_MIN; } }&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Dans &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;loop()&lt;/code&gt;, nous allons appeler cette fonction &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;gereServo&lt;/code&gt; pour chacun des servos. Pour cela nous allons faire une boucle &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;for( ... ; ... ; ... )&lt;/code&gt;. Pour parcourir tous les servos, nous allons &#233;crire &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;for( numServo = 0; numServo &lt; 8; numServo++)&lt;/code&gt;. Le &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;numServo = 0;&lt;/code&gt; est ex&#233;cut&#233; une fois au d&#233;but de la boucle. il s'agit de l'initialisation. Le &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;numServo &lt; 8&lt;/code&gt; est une condition qui est test&#233;e au d&#233;but de chaque &lt;i&gt;it&#233;ration&lt;/i&gt;. Si la condition est vraie, la boucle continue, sinon elle s'arr&#234;te. Enfin le &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;numServo++&lt;/code&gt; est ex&#233;cut&#233; &#224; la fin de chaque it&#233;ration de la boucle, numServo est augment&#233; de 1. Par cons&#233;quent, cette boucle va produire 8 it&#233;rations et numServo vaudra successivement 0, 1, 2, 3, 4, 5, 6 et 7, ce qui correspond bien au parcours des &#233;l&#233;ments de notre tableau servoMoteur.&lt;/p&gt;
&lt;p&gt;G&#233;rer les 8 servos est donc pris en charge par cette ligne dans &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;loop()&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;code data-raccourci=&#034;code&#034; data-language=&#034;C&#034; class='spip_code spip_code_inline language-C' dir='ltr'&gt;for (numServo = 0; numServo &lt; 8; numServo++) gereServo(numServo);&lt;/code&gt;&lt;/p&gt;
&lt;h2 class=&#034;spip&#034;&gt;Int&#233;gration de la commande par poussoir&lt;/h2&gt;
&lt;p&gt;Dans &#171; &lt;a href='https://modelleisenbahn.triskell.org/spip.php?article58' class=&#034;spip_in&#034;&gt;Commande du servo-moteur par bouton poussoir&lt;/a&gt; &#187;, L'unique poussoir &#233;tait lu et la vitesse du servo &#233;tait chang&#233;e. Comme ceci.&lt;/p&gt;
&lt;div class=&#034;precode&#034;&gt;&lt;pre data-raccourci=&#034;code&#034; data-language=&#034;C&#034; class='spip_code spip_code_block language-C' dir='ltr' style='text-align:left;'&gt;&lt;code&gt; byte evenement = lireEvenement(); if (evenement == EVENEMENT_PRESSE) { switch (etatServo) { case SERVO_A_ANGLE_MIN: case SERVO_EN_MOUVEMENT_VERS_ANGLE_MIN: vitesse = 1; etatServo = SERVO_EN_MOUVEMENT_VERS_ANGLE_MAX; break; case SERVO_A_ANGLE_MAX: case SERVO_EN_MOUVEMENT_VERS_ANGLE_MAX: vitesse = -1; etatServo = SERVO_EN_MOUVEMENT_VERS_ANGLE_MIN; break; } }&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Nous allons isoler le &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;switch ... case&lt;/code&gt; dans une fonction que nous appelons &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;evenementServo(...)&lt;/code&gt; et dont l'argument est le num&#233;ro de servo. Ce num&#233;ro de servo est le num&#233;ro de bouton press&#233;. Il suffit alors de modifier la vitesse du servo correspondant. Comme ceci.&lt;/p&gt;
&lt;div class=&#034;precode&#034;&gt;&lt;pre data-raccourci=&#034;code&#034; data-language=&#034;C&#034; class='spip_code spip_code_block language-C' dir='ltr' style='text-align:left;'&gt;&lt;code&gt;void evenementServo(int numServo) { switch (servoMoteur[numServo].etatServo) { case SERVO_A_ANGLE_MIN: case SERVO_EN_MOUVEMENT_VERS_ANGLE_MIN: servoMoteur[numServo].vitesse = 1; servoMoteur[numServo].etatServo = SERVO_EN_MOUVEMENT_VERS_ANGLE_MAX; break; case SERVO_A_ANGLE_MAX: case SERVO_EN_MOUVEMENT_VERS_ANGLE_MAX: servoMoteur[numServo].vitesse = -1; servoMoteur[numServo].etatServo = SERVO_EN_MOUVEMENT_VERS_ANGLE_MIN; break; } }&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Il ne reste plus qu'&#224; lire l'&#233;v&#233;nement du bouton comme dans &#171; &lt;a href='https://modelleisenbahn.triskell.org/spip.php?article59' class=&#034;spip_in&#034;&gt;Plusieurs boutons poussoir sur une entr&#233;e analogique&lt;/a&gt; &#187; et &#224; appeler la fonction &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;evenementServo(...)&lt;/code&gt; avec le num&#233;ro de bouton recueilli.&lt;/p&gt;
&lt;div class=&#034;precode&#034;&gt;&lt;pre data-raccourci=&#034;code&#034; data-language=&#034;C&#034; class='spip_code spip_code_block language-C' dir='ltr' style='text-align:left;'&gt;&lt;code&gt; byte evenement = lireEvenement(&amp;numServo); if (evenement == EVENEMENT_PRESSE) evenementServo(numServo);&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Le programme complet est le suivant.&lt;/p&gt;
&lt;div class=&#034;precode&#034;&gt;&lt;pre data-raccourci=&#034;code&#034; data-language=&#034;C&#034; class='spip_code spip_code_block language-C' dir='ltr' style='text-align:left;'&gt;&lt;code&gt;#include &lt;Servo.h&gt; const byte SERVO_A_ANGLE_MIN = 0; const byte SERVO_A_ANGLE_MAX = 1; const byte SERVO_EN_MOUVEMENT_VERS_ANGLE_MAX = 2; const byte SERVO_EN_MOUVEMENT_VERS_ANGLE_MIN = 3; const int angleMin = 1250; const int angleMax = 1750; struct DescripteurServo { Servo objetServo; int vitesse; int angle; byte etatServo; }; struct DescripteurServo servoMoteur[8]; const byte NON_PRESSE = 0; const byte ENFONCE = 1; const byte PRESSE = 2; byte etatAutomate = NON_PRESSE; int etatPoussoir = -1; const byte AUCUN_EVENEMENT = 0; const byte EVENEMENT_PRESSE = 1; const byte EVENEMENT_RELACHE = 2; const int pinPoussoirs = 0; /* * Lecture des poussoirs. &#192; l'aide d'un automate, on assure que les valeurs * transitoires sont filtr&#233;es. */ int lirePoussoirs() { int resultat; int numPoussoir = (analogRead(pinPoussoirs) + 64) / 128; int nouvelEtatPoussoir = etatPoussoir; /* &#224; priori rien ne change */ switch (etatAutomate) { case NON_PRESSE: if (numPoussoir &lt; 8) etatAutomate = ENFONCE; break; case ENFONCE: if (numPoussoir &lt; 8) { etatAutomate = PRESSE; nouvelEtatPoussoir = numPoussoir; } else { etatAutomate = NON_PRESSE; } break; case PRESSE: if (numPoussoir == 8) { etatAutomate = NON_PRESSE; nouvelEtatPoussoir = -1; } break; } return nouvelEtatPoussoir; } /* * construction d'un &#233;v&#233;nement en comparant * le nouvel &#233;tat des poussoirs avec l'&#233;tat pr&#233;c&#233;dent. */ byte lireEvenement(int *numPoussoir) { byte evenement; int nouvelEtatPoussoir = lirePoussoirs(); if (nouvelEtatPoussoir == etatPoussoir) evenement = AUCUN_EVENEMENT; if (nouvelEtatPoussoir &gt;= 0 &amp;&amp; etatPoussoir == -1) evenement = EVENEMENT_PRESSE; if (nouvelEtatPoussoir == -1 &amp;&amp; etatPoussoir &gt;= 0) evenement = EVENEMENT_RELACHE; etatPoussoir = nouvelEtatPoussoir; *numPoussoir = etatPoussoir; return evenement; } /* * Initialisations. Chaque servomoteur est initialis&#233; &#224; l'angle minimum * sa vitesse est mise &#224; 0 */ void setup() { /* Initialisation des servos */ int numServo; for (numServo = 0; numServo &lt; 8; numServo++) { servoMoteur[numServo].angle = angleMin; servoMoteur[numServo].vitesse = 0; servoMoteur[numServo].etatServo = SERVO_A_ANGLE_MIN; servoMoteur[numServo].objetServo.attach(numServo+2); } } /* * Actualisation de l'angle du servo */ void gereServo(int numServo) { servoMoteur[numServo].objetServo.writeMicroseconds( servoMoteur[numServo].angle); servoMoteur[numServo].angle += servoMoteur[numServo].vitesse; if (servoMoteur[numServo].angle &gt; angleMax) { servoMoteur[numServo].angle = angleMax; servoMoteur[numServo].vitesse = 0; servoMoteur[numServo].etatServo = SERVO_A_ANGLE_MAX; } else if (servoMoteur[numServo].angle &lt; angleMin) { servoMoteur[numServo].angle = angleMin; servoMoteur[numServo].vitesse = 0; servoMoteur[numServo].etatServo = SERVO_A_ANGLE_MIN; } } /* * changement de consigne d'un servomoteur. */ void evenementServo(int numServo) { switch (servoMoteur[numServo].etatServo) { case SERVO_A_ANGLE_MIN: case SERVO_EN_MOUVEMENT_VERS_ANGLE_MIN: servoMoteur[numServo].vitesse = 1; servoMoteur[numServo].etatServo = SERVO_EN_MOUVEMENT_VERS_ANGLE_MAX; break; case SERVO_A_ANGLE_MAX: case SERVO_EN_MOUVEMENT_VERS_ANGLE_MAX: servoMoteur[numServo].vitesse = -1; servoMoteur[numServo].etatServo = SERVO_EN_MOUVEMENT_VERS_ANGLE_MIN; break; } } void loop() { int numServo; for (numServo = 0; numServo &lt; 8; numServo++) gereServo(numServo); byte evenement = lireEvenement(&amp;numServo); if (evenement == EVENEMENT_PRESSE) evenementServo(numServo); delay(3); }&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 class=&#034;spip&#034;&gt;Coupure de la commande dans les positions extr&#234;mes&lt;/h2&gt;
&lt;p&gt;Jusqu'&#224; maintenant, une fois qu'un servomoteur a gagn&#233; une de ses deux positions extr&#234;mes, la commande PWM de position reste active. Par cons&#233;quent l'&#233;lectronique du servomoteur continue d'asservir la position. Or, en pr&#233;sence d'une r&#233;sistance m&#233;canique comme par exemple l'effet ressort de la tige de commande de l'aiguille, l'asservissement de position fait que le servomoteur grogne. C'est un inconv&#233;nient, &#224; la fois pour les oreilles et pour la consommation &#233;lectrique.&lt;/p&gt;
&lt;p&gt;Pour supprimer cet asservissement une fois que le servomoteur a accompli son mouvement, il suffit de couper la commande PWM. Ce n'est pas explicitement pr&#233;vu dans la biblioth&#232;que Servo de l'Arduino mais il suffit de d&#233;tacher le servo de la broche de sortie par la m&#233;thode &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;detach()&lt;/code&gt; pour couper la commande PWM.&lt;/p&gt;
&lt;p&gt;Pour simplifier le programme, on va ajouter dans &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;DescripteurServo&lt;/code&gt; un membre pour stocker le num&#233;ro de broche. Appelons le &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;pin&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&#034;precode&#034;&gt;&lt;pre data-raccourci=&#034;code&#034; data-language=&#034;C&#034; class='spip_code spip_code_block language-C' dir='ltr' style='text-align:left;'&gt;&lt;code&gt;struct DescripteurServo { Servo objetServo; int vitesse; int angle; int pin; byte etatServo; };&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Il faut &#233;videmment ne pas oublier d'initialiser &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;pin&lt;/code&gt; dans &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;setup()&lt;/code&gt;&lt;/p&gt;
&lt;div class=&#034;precode&#034;&gt;&lt;pre data-raccourci=&#034;code&#034; data-language=&#034;C&#034; class='spip_code spip_code_block language-C' dir='ltr' style='text-align:left;'&gt;&lt;code&gt; for (numServo = 0; numServo &lt; 8; numServo++) { servoMoteur[numServo].angle = angleMin; servoMoteur[numServo].vitesse = 0; servoMoteur[numServo].etatServo = SERVO_A_ANGLE_MIN; servoMoteur[numServo].pin = numServo + 2; servoMoteur[numServo].objetServo.attach(servoMoteur[numServo].pin); }&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Dans la fonction &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;gereServo(...)&lt;/code&gt; on va d&#233;tacher le servo quand une des positions extr&#234;mes est atteinte.&lt;/p&gt;
&lt;div class=&#034;precode&#034;&gt;&lt;pre data-raccourci=&#034;code&#034; data-language=&#034;C&#034; class='spip_code spip_code_block language-C' dir='ltr' style='text-align:left;'&gt;&lt;code&gt; if (servoMoteur[numServo].angle &gt; angleMax) { servoMoteur[numServo].angle = angleMax; servoMoteur[numServo].vitesse = 0; servoMoteur[numServo].objetServo.detach(); servoMoteur[numServo].etatServo = SERVO_A_ANGLE_MAX; } else if (servoMoteur[numServo].angle &lt; angleMin) { servoMoteur[numServo].angle = angleMin; servoMoteur[numServo].vitesse = 0; servoMoteur[numServo].objetServo.detach(); servoMoteur[numServo].etatServo = SERVO_A_ANGLE_MIN; }&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Enfin, dans la fonction &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;evenementServo&lt;/code&gt;, on va attacher de nouveau le servo &#224; la broche quand si le servo est dans une des positions extr&#234;mes. On voit ici l'int&#233;r&#234;t d'avoir s&#233;parer les cas SERVO_A_ANGLE_x et SERVO_EN_MOUVEMENT_VERS_ANGLE_x car pour le second il ne faut pas attacher le servo &#224; la broche.&lt;/p&gt;
&lt;div class=&#034;precode&#034;&gt;&lt;pre data-raccourci=&#034;code&#034; data-language=&#034;C&#034; class='spip_code spip_code_block language-C' dir='ltr' style='text-align:left;'&gt;&lt;code&gt;void evenementServo(int numServo) { switch (servoMoteur[numServo].etatServo) { case SERVO_A_ANGLE_MIN: servoMoteur[numServo].objetServo.attach(servoMoteur[numServo].pin); case SERVO_EN_MOUVEMENT_VERS_ANGLE_MIN: servoMoteur[numServo].vitesse = 1; servoMoteur[numServo].etatServo = SERVO_EN_MOUVEMENT_VERS_ANGLE_MAX; break; case SERVO_A_ANGLE_MAX: servoMoteur[numServo].objetServo.attach(servoMoteur[numServo].pin); case SERVO_EN_MOUVEMENT_VERS_ANGLE_MAX: servoMoteur[numServo].vitesse = -1; servoMoteur[numServo].etatServo = SERVO_EN_MOUVEMENT_VERS_ANGLE_MIN; break; } }&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Le programme devenant plus gros, je vais cesser de donner son code in-extenso sur les pages du blog. Le voici donc &#224; t&#233;l&#233;charger&lt;/p&gt;
&lt;div class='spip_document_277 spip_document spip_documents spip_document_file spip_document_avec_legende' data-legende-len=&#034;51&#034; data-legende-lenx=&#034;x&#034;
&gt;
&lt;figure class=&#034;spip_doc_inner&#034;&gt;
&lt;a href='https://modelleisenbahn.triskell.org/IMG/zip/Huit_boutons_huit_servos_detach-3.zip' class=&#034; spip_doc_lien&#034; title='Zip - 1.4 kio' type=&#034;application/zip&#034;&gt;&lt;img src='https://modelleisenbahn.triskell.org/local/cache-vignettes/L64xH64/zip-f045b.svg?1772799586' width='64' height='64' alt='' /&gt;&lt;/a&gt;
&lt;figcaption class='spip_doc_legende'&gt; &lt;div class='spip_doc_titre crayon document-titre-277 '&gt;&lt;strong&gt;Programme Arduino avec coupure de la commande PWM
&lt;/strong&gt;&lt;/div&gt; &lt;/figcaption&gt;&lt;/figure&gt;
&lt;/div&gt;&lt;h2 class=&#034;spip&#034;&gt;Les essais&lt;/h2&gt;&lt;blockquote class=&#034;spip&#034;&gt;
&lt;p&gt;&lt;strong&gt;Attention&lt;/strong&gt;, avec 8 servomoteurs tirant sur l'alimentation de l'Arduino, il faut prendre certaines pr&#233;cautions. Il faut tout d'abord s'assurer que la consommation totale n'exc&#232;de pas ce que l'Arduino peut fournir. Son r&#233;gulateur de tension est donn&#233; pour 1A mais la carte elle-m&#234;me consomme.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Pour mes exp&#233;rimentations j'ai mesur&#233; la consommation des servos HK15178. Au repos, il consomment 7mA. En mouvement &#224; la vitesse impos&#233;e, ils montent &#224; un peu moins de 60mA. Si il n'y qu'un seul servo en mouvement &#224; un instant, l'ensemble va donc consommer 7 &#215; 7mA + 60mA = 110mA ce qui reste raisonnable. Bloqu&#233;, il consomme 150mA. Dans les faits la connexion du 6e servo a provoqu&#233; la coupure de l'alimentation car le r&#233;gulateur a d&#233;tect&#233; une consommation excessive. Comme d&#233;j&#224; indiqu&#233; dans &#171; &lt;a href='https://modelleisenbahn.triskell.org/spip.php?article36' class=&#034;spip_in&#034;&gt;La carte de commande 6 servo-moteurs, le mat&#233;riel&lt;/a&gt; &#187;, l'appel de courant lors de la mise sous tension d'un servomoteur peut &#234;tre important.&lt;/p&gt;
&lt;p&gt;Pour une installation sur le r&#233;seau, il est donc pr&#233;f&#233;rable de pr&#233;voir une alimentation s&#233;par&#233;e pour les servomoteurs.&lt;/p&gt;
&lt;p&gt;Voici la vid&#233;o des essais.&lt;/p&gt;
&lt;div class=&#034;spip_document_270 spip_document spip_documents spip_document_video&#034;&gt;
&lt;figure class=&#034;spip_doc_inner&#034;&gt;
&lt;div class=&#034;video-intrinsic-wrapper&#034; style='height:0;width:640px;max-width:100%;padding-bottom:56.25%;position:relative;'&gt; &lt;div class=&#034;video-wrapper&#034; style=&#034;position: absolute;top:0;left:0;width:100%;height:100%;&#034;&gt; &lt;video class=&#034;mejs mejs-270&#034; data-id=&#034;3d79cd4c58bb6325c6cd9345e9fdb9ff&#034; data-mejsoptions='{&#034;iconSprite&#034;: &#034;plugins-dist/medias/lib/mejs/mejs-controls.svg&#034;,&#034;alwaysShowControls&#034;: true,&#034;pluginPath&#034;:&#034;plugins-dist/medias/lib/mejs/&#034;,&#034;loop&#034;:false,&#034;videoWidth&#034;:&#034;100%&#034;,&#034;videoHeight&#034;:&#034;100%&#034;}' width=&#034;100%&#034; height=&#034;100%&#034; controls=&#034;controls&#034; preload=&#034;none&#034; &gt; &lt;source type=&#034;application/x-shockwave-flash&#034; src=&#034;http://www.youtube.com/v/9iFSObeONTY?hl=fr_FR&amp;version=3&amp;rel=0&#034; /&gt; &lt;img src='https://modelleisenbahn.triskell.org/local/cache-vignettes/L64xH64/swf-d2c4d-75a7b.svg?1772798901' width='64' height='64' alt='Impossible de lire la video' /&gt; &lt;/video&gt; &lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#034;base64javascript20209960069f2c6729ef848.51775611&#034; title=&#034;PHNjcmlwdD4gdmFyIG1lanNwYXRoPSdwbHVnaW5zLWRpc3QvbWVkaWFzL2xpYi9tZWpzL21lZGlhZWxlbWVudC1hbmQtcGxheWVyLm1pbi5qcz8xNzcyNzk1ODQwJyxtZWpzY3NzPSdwbHVnaW5zLWRpc3QvbWVkaWFzL2xpYi9tZWpzL21lZGlhZWxlbWVudHBsYXllci5taW4uY3NzPzE3NzI3OTU4NDAnOwp2YXIgbWVqc2xvYWRlcjsKKGZ1bmN0aW9uKCl7dmFyIGE9bWVqc2xvYWRlcjsidW5kZWZpbmVkIj09dHlwZW9mIGEmJihtZWpzbG9hZGVyPWE9e2dzOm51bGwscGx1Zzp7fSxjc3M6e30saW5pdDpudWxsLGM6MCxjc3Nsb2FkOm51bGx9KTthLmluaXR8fChhLmNzc2xvYWQ9ZnVuY3Rpb24oYyl7aWYoInVuZGVmaW5lZCI9PXR5cGVvZiBhLmNzc1tjXSl7YS5jc3NbY109ITA7dmFyIGI9ZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgibGluayIpO2IuaHJlZj1jO2IucmVsPSJzdHlsZXNoZWV0IjtiLnR5cGU9InRleHQvY3NzIjtkb2N1bWVudC5nZXRFbGVtZW50c0J5VGFnTmFtZSgiaGVhZCIpWzBdLmFwcGVuZENoaWxkKGIpfX0sYS5pbml0PWZ1bmN0aW9uKCl7ITA9PT1hLmdzJiZmdW5jdGlvbihjKXtqUXVlcnkoImF1ZGlvLm1lanMsdmlkZW8ubWVqcyIpLm5vdCgiLmRvbmUsLm1lanNfX3BsYXllciIpLmVhY2goZnVuY3Rpb24oKXtmdW5jdGlvbiBiKCl7dmFyIGU9ITAsaDtmb3IoaCBpbiBkLmNzcylhLmNzc2xvYWQoZC5jc3NbaF0pO2Zvcih2YXIgZiBpbiBkLnBsdWdpbnMpInVuZGVmaW5lZCI9PQp0eXBlb2YgYS5wbHVnW2ZdPyhlPSExLGEucGx1Z1tmXT0hMSxqUXVlcnkuZ2V0U2NyaXB0KGQucGx1Z2luc1tmXSxmdW5jdGlvbigpe2EucGx1Z1tmXT0hMDtiKCl9KSk6MD09YS5wbHVnW2ZdJiYoZT0hMSk7ZSYmalF1ZXJ5KCIjIitjKS5tZWRpYWVsZW1lbnRwbGF5ZXIoalF1ZXJ5LmV4dGVuZChkLm9wdGlvbnMse3N1Y2Nlc3M6ZnVuY3Rpb24oYSxjKXtmdW5jdGlvbiBiKCl7dmFyIGI9alF1ZXJ5KGEpLmNsb3Nlc3QoIi5tZWpzX19pbm5lciIpO2EucGF1c2VkPyhiLmFkZENsYXNzKCJwYXVzaW5nIiksc2V0VGltZW91dChmdW5jdGlvbigpe2IuZmlsdGVyKCIucGF1c2luZyIpLnJlbW92ZUNsYXNzKCJwbGF5aW5nIikucmVtb3ZlQ2xhc3MoInBhdXNpbmciKS5hZGRDbGFzcygicGF1c2VkIil9LDEwMCkpOmIucmVtb3ZlQ2xhc3MoInBhdXNlZCIpLnJlbW92ZUNsYXNzKCJwYXVzaW5nIikuYWRkQ2xhc3MoInBsYXlpbmciKX1iKCk7YS5hZGRFdmVudExpc3RlbmVyKCJwbGF5IixiLCExKTsKYS5hZGRFdmVudExpc3RlbmVyKCJwbGF5aW5nIixiLCExKTthLmFkZEV2ZW50TGlzdGVuZXIoInBhdXNlIixiLCExKTthLmFkZEV2ZW50TGlzdGVuZXIoInBhdXNlZCIsYiwhMSk7Zy5hdHRyKCJhdXRvcGxheSIpJiZhLnBsYXkoKX19KSl9dmFyIGc9alF1ZXJ5KHRoaXMpLmFkZENsYXNzKCJkb25lIiksYzsoYz1nLmF0dHIoImlkIikpfHwoYz0ibWVqcy0iK2cuYXR0cigiZGF0YS1pZCIpKyItIithLmMrKyxnLmF0dHIoImlkIixjKSk7dmFyIGQ9e29wdGlvbnM6e30scGx1Z2luczp7fSxjc3M6W119LGUsaDtmb3IoZSBpbiBkKWlmKGg9Zy5hdHRyKCJkYXRhLW1lanMiK2UpKWRbZV09alF1ZXJ5LnBhcnNlSlNPTihoKTtiKCl9KX0oalF1ZXJ5KX0pO2EuZ3N8fCgidW5kZWZpbmVkIiE9PXR5cGVvZiBtZWpzY3NzJiZhLmNzc2xvYWQobWVqc2NzcyksYS5ncz1qUXVlcnkuZ2V0U2NyaXB0KG1lanNwYXRoLGZ1bmN0aW9uKCl7YS5ncz0hMDthLmluaXQoKTtqUXVlcnkoYS5pbml0KTtvbkFqYXhMb2FkKGEuaW5pdCl9KSl9KSgpOzwvc2NyaXB0Pg==&#034;&gt;&lt;/div&gt; &lt;/figure&gt;
&lt;/div&gt;
&lt;p&gt;La prochain article sera consacr&#233; &#224; l'ajout de la fonction de r&#233;glage des but&#233;es.&lt;/p&gt;&lt;/div&gt;
		&lt;hr /&gt;
		&lt;div class='rss_notes'&gt;&lt;div id=&#034;nb2-1&#034;&gt;
&lt;p&gt;&lt;span class=&#034;spip_note_ref&#034;&gt;[&lt;a href=&#034;#nh2-1&#034; class=&#034;spip_note&#034; title=&#034;Notes 2-1&#034; rev=&#034;appendix&#034;&gt;1&lt;/a&gt;] &lt;/span&gt;Oui le 5e puisque le premier &#224; le num&#233;ro 0&lt;/p&gt;
&lt;/div&gt;&lt;/div&gt;
		
		</content:encoded>


		

	</item>
<item xml:lang="fr">
		<title>Plusieurs boutons poussoir sur une entr&#233;e analogique</title>
		<link>https://modelleisenbahn.triskell.org/spip.php?article59</link>
		<guid isPermaLink="true">https://modelleisenbahn.triskell.org/spip.php?article59</guid>
		<dc:date>2013-11-16T22:11:12Z</dc:date>
		<dc:format>text/html</dc:format>
		<dc:language>fr</dc:language>
		<dc:creator>Jean-Luc</dc:creator>


		<dc:subject>aiguille</dc:subject>
		<dc:subject>servo</dc:subject>
		<dc:subject>Arduino</dc:subject>

		<description>
&lt;p&gt;Dans &#171; Commande du servo-moteur par bouton poussoir &#187;, nous avons vu comment connecter un bouton poussoir &#224; une entr&#233;e analogique. Dans celui-ci nous allons voir comment en connecter plusieurs et lire lequel est enfonc&#233;. &lt;br class='autobr' /&gt;
Cette id&#233;e de connecter plusieurs poussoirs sur une entr&#233;e analogique n'est pas nouvelle. Une Application Note de Freescale existe et l'id&#233;e m'a &#233;t&#233; souffl&#233;e par Marc-Henri que je remercie au passage. &lt;br class='autobr' /&gt; Marc-Henri vient de publier un article sur son blog qui d&#233;crit (&#8230;)&lt;/p&gt;


-
&lt;a href="https://modelleisenbahn.triskell.org/spip.php?rubrique22" rel="directory"&gt;Man&#339;uvre des aiguilles avec des servo-moteurs&lt;/a&gt;

/ 
&lt;a href="https://modelleisenbahn.triskell.org/spip.php?mot4" rel="tag"&gt;aiguille&lt;/a&gt;, 
&lt;a href="https://modelleisenbahn.triskell.org/spip.php?mot5" rel="tag"&gt;servo&lt;/a&gt;, 
&lt;a href="https://modelleisenbahn.triskell.org/spip.php?mot10" rel="tag"&gt;Arduino&lt;/a&gt;

		</description>


 <content:encoded>&lt;div class='rss_texte'&gt;&lt;p&gt;Dans &#171; &lt;a href='https://modelleisenbahn.triskell.org/spip.php?article58' class=&#034;spip_in&#034;&gt;Commande du servo-moteur par bouton poussoir&lt;/a&gt; &#187;, nous avons vu comment connecter un bouton poussoir &#224; une entr&#233;e analogique. Dans celui-ci nous allons voir comment en connecter plusieurs et lire lequel est enfonc&#233;.&lt;/p&gt;
&lt;p&gt;Cette id&#233;e de connecter plusieurs poussoirs sur une entr&#233;e analogique n'est pas nouvelle. Une &lt;a href=&#034;http://www.google.com/url?sa=t&amp;rct=j&amp;q=&amp;esrc=s&amp;source=web&amp;cd=1&amp;ved=0CD8QFjAA&amp;url=http%3A%2F%2Fwww.freescale.com%2Ffiles%2Fmicrocontrollers%2Fdoc%2Fapp_note%2FAN1775.pdf&amp;ei=N-mBUvfhOqSL0AXGjYDwAw&amp;usg=AFQjCNFrcxi0FKUV0ecL8sXGIpLDyUouQg&amp;sig2=fqTCJzuf9lbYd3E8jc0jVg&amp;bvm=bv.56146854,d.d2k&#034; class=&#034;spip_out&#034; rel=&#034;external&#034;&gt;&lt;i&gt;Application Note&lt;/i&gt; de Freescale&lt;/a&gt; existe et l'id&#233;e m'a &#233;t&#233; souffl&#233;e par &lt;a href=&#034;http://savignyexpress.wordpress.com&#034; class=&#034;spip_out&#034; rel=&#034;external&#034;&gt;Marc-Henri&lt;/a&gt; que je remercie au passage.&lt;/p&gt;
&lt;blockquote class=&#034;spip&#034;&gt;
&lt;p&gt;
Marc-Henri vient de publier un &lt;a href=&#034;http://savignyexpress.wordpress.com/2013/11/18/connecter-plusieurs-boutons-poussoir-a-un-microcontroleur/&#034; class=&#034;spip_out&#034; rel=&#034;external&#034;&gt;article sur son blog&lt;/a&gt; qui d&#233;crit pr&#233;cis&#233;ment le calcul des r&#233;sistances ainsi qu'une &lt;a href=&#034;http://savignyexpress.files.wordpress.com/2013/11/clavieranalogique.xls&#034; class=&#034;spip_out&#034; rel=&#034;external&#034;&gt;feuille de calcul&lt;/a&gt; (format Excel) le mettant en &#339;uvre pour un nombre quelconque de poussoirs&lt;/p&gt;
&lt;/blockquote&gt;&lt;h2 class=&#034;spip&#034;&gt;Principe de fonctionnement&lt;/h2&gt;
&lt;p&gt;Avec un seul poussoir, nous avons vu que l'entr&#233;e analogique de l'Arduino &#233;tait tir&#233;e &#224; la masse via une r&#233;sistance de 10k&#937;. L'appui sur le poussoir amenait cette entr&#233;e &#224; 5V. Pour la suite, on va inverser la connexion. L'entr&#233;e analogique esr tir&#233;e &#224; +5V et l'appui sur le poussoir am&#232;ne cette entr&#233;e &#224; la masse. En effet, avec plusieurs poussoirs, cette fa&#231;on de faire est plus commode car, sur le r&#233;seau, la masse est distribu&#233;e partout alors que ce n'est pas le cas pour le +5V.&lt;/p&gt;
&lt;div class='spip_document_258 spip_document spip_documents spip_document_image spip_documents_center spip_document_center spip_document_avec_legende' data-legende-len=&#034;85&#034; data-legende-lenx=&#034;xx&#034;
&gt;
&lt;figure class=&#034;spip_doc_inner&#034;&gt; &lt;img src='https://modelleisenbahn.triskell.org/local/cache-vignettes/L490xH558/poussoir_gnd-33a32.png?1692301737' width='490' height='558' alt='' /&gt;
&lt;figcaption class='spip_doc_legende'&gt; &lt;div class='spip_doc_titre crayon document-titre-258 '&gt;&lt;strong&gt;Connexion d'un poussoir &#224; l'entr&#233;e analogique de l'Arduino Uno, &#233;tat de repos &#224; +5V
&lt;/strong&gt;&lt;/div&gt; &lt;/figcaption&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;p&gt;Imaginons maintenant que nous ajoutions un second poussoir en parall&#232;le du premier et qu'il soit connect&#233; entre l'entr&#233;e analogique de l'Arduino et la masse via une r&#233;sistance, &#233;galement de 10k&#937;, comme ceci.&lt;/p&gt;
&lt;div class='spip_document_260 spip_document spip_documents spip_document_image spip_documents_center spip_document_center spip_document_avec_legende' data-legende-len=&#034;53&#034; data-legende-lenx=&#034;x&#034;
&gt;
&lt;figure class=&#034;spip_doc_inner&#034;&gt; &lt;img src='https://modelleisenbahn.triskell.org/local/cache-vignettes/L500xH457/poussoir_double_gnd-2-18090.png?1692301737' width='500' height='457' alt='' /&gt;
&lt;figcaption class='spip_doc_legende'&gt; &lt;div class='spip_doc_titre crayon document-titre-260 '&gt;&lt;strong&gt;Connexion de deux poussoirs &#224; une entr&#233;e analogique
&lt;/strong&gt;&lt;/div&gt; &lt;/figcaption&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;p&gt;Lorsque &lt;strong&gt;B0&lt;/strong&gt; est press&#233;, nous avons le m&#234;me comportement, l'entr&#233;e analogique est &#224; 0V. Lorsque &lt;strong&gt;B1&lt;/strong&gt; est press&#233;, les deux r&#233;sistances sont en s&#233;rie entre 5V et 0V et l'entr&#233;e analogique est &#224; la tension qui existe entre les deux r&#233;sistances. On voit qu'il s'agit d'un &lt;a href=&#034;http://fr.wikipedia.org/wiki/Diviseur_de_tension&#034; class=&#034;spip_out&#034; rel=&#034;external&#034;&gt;diviseur de tension&lt;/a&gt;, et donc l'entr&#233;e analogique est &#224; 2,5V. Evidemment, on ne peut pas presser 2 poussoirs en m&#234;me temps, l'Arduino ne verra que le poussoir de rang le plus bas.&lt;/p&gt;
&lt;p&gt;On peut continuer &#224; ajouter des poussoirs en parall&#232;le avec la r&#233;sistance ad&#233;quate pour que le diviseur de tension donne une tension pr&#233;cise pour chaque poussoir. Pour nos 8 boutons-poussoir, nous allons proc&#233;der de cette mani&#232;re.&lt;/p&gt;
&lt;div class='spip_document_261 spip_document spip_documents spip_document_image spip_documents_center spip_document_center spip_document_avec_legende' data-legende-len=&#034;50&#034; data-legende-lenx=&#034;x&#034;
&gt;
&lt;figure class=&#034;spip_doc_inner&#034;&gt; &lt;img src='https://modelleisenbahn.triskell.org/local/cache-vignettes/L500xH401/8_poussoirs-e055b.png?1692301737' width='500' height='401' alt='' /&gt;
&lt;figcaption class='spip_doc_legende'&gt; &lt;div class='spip_doc_titre crayon document-titre-261 '&gt;&lt;strong&gt;Connexion de 8 poussoirs &#224; une entr&#233;e analogique
&lt;/strong&gt;&lt;/div&gt; &lt;/figcaption&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;p&gt;Avec 8 poussoirs, il faut diviser les 1024 valeurs possibles en 8 intervalles de 1024 &#247; 8 = 128 valeurs. Plus on ajoute des poussoirs et plus cet intervalle devient petit. Plus cet intervalle devient petit et plus il est n&#233;cessaire d'avoir des r&#233;sistances pr&#233;cises. Or, les r&#233;sistances standards ont des valeurs d&#233;termin&#233;es et sont pr&#233;cises &#224; 5%. Si les intervalles sont trop petits, il devient impossible de distinguer deux valeurs voisines de fa&#231;on fiable. Cela limite le nombre de poussoirs que l'on peut connecter mais 8 poussoirs ne devraient pas poser de probl&#232;me.&lt;/p&gt;
&lt;div class='spip_document_264 spip_document spip_documents spip_document_image spip_documents_center spip_document_center'&gt;
&lt;figure class=&#034;spip_doc_inner&#034;&gt; &lt;img src='https://modelleisenbahn.triskell.org/local/cache-vignettes/L420xH387/decoupage_plage-2-ba260.png?1692301737' width='420' height='387' alt='' /&gt;
&lt;/figure&gt;
&lt;/div&gt;
&lt;p&gt;Sur la figure pr&#233;c&#233;dente, la plage de valeurs analogiques a &#233;t&#233; d&#233;coup&#233;e en 8 intervalles. En (a) le poussoir press&#233;, en (b) la tension correspondante, en (c) la valeur num&#233;rique, en (d) cette m&#234;me valeur num&#233;rique en binaire. Il faut donc d&#233;terminer les r&#233;sistances R1 &#224; R7 de mani&#232;re &#224; obtenir plus ou moins la tension voulue. On va voir que &#231;a se fait assez bien.&lt;/p&gt;
&lt;p&gt;Une fois une valeur analogique num&#233;ris&#233;e, il faut d&#233;terminer par programme de quel poussoir il s'agit. On peut le faire par une succession de &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;if ... else ...&lt;/code&gt; en testant la valeur lue par rapport au milieu des intervalles : entre 0 et 63, aucun poussoir n'est press&#233;, entre 63 et 191, B0 est press&#233;, entre 192 et 319, B1 est press&#233;, etc. Mais c'est un peu long. On peut &#233;crire cela de mani&#232;re plus concise, un programmeur est un fain&#233;ant, moins il &#233;crit de code, mieux il se porte.&lt;/p&gt;
&lt;p&gt;Pour cela, nous allons diviser la valeur lue par la taille de l'intervalle (128).&lt;br class='autobr' /&gt;
Il s'agit &#233;videmment d'une division enti&#232;re, le r&#233;sultat donnerait le num&#233;ro du poussoir press&#233;, il s'agit des 3 bits de poids fort dans la colonne (d), ceux qui sont s&#233;par&#233;s des autres. Malheureusement, on peut voir que ce r&#233;sultat change au voisinage de la valeur lue. Par exemple au voisinage de 127, le r&#233;sultat peut &#234;tre 0 ou 1 et au voisinage de 255, le r&#233;sultat peut &#234;tre 1 ou 2. Par cons&#233;quent on peut confondre les deux poussoirs !&lt;/p&gt;
&lt;p&gt;Pour malgr&#233; tout proc&#233;der de cette mani&#232;re, il suffit de d&#233;caler l'intervalle. En ajoutant la moiti&#233; de la taille de l'intervalle &#224; la valeur lue, 64 donc, le r&#233;sultat donn&#233; pas la division enti&#232;re est directement le num&#233;ro du poussoir (de 0 &#224; 7), ou bien 8 si aucun poussoir n'est press&#233;, et ce num&#233;ro est stable et centr&#233; au voisinage des valeurs lues, comme montr&#233; &#224; la colonne (d). La d&#233;termination du poussoir press&#233; se fait alors en une ligne de code.&lt;/p&gt;
&lt;p&gt;&lt;code data-raccourci=&#034;code&#034; data-language=&#034;C&#034; class='spip_code spip_code_inline language-C' dir='ltr'&gt;int numPoussoir = (analogRead(pinPoussoirs) + 64) / 128;&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Cette concision ne peut que r&#233;jouir le programmeur ^_^&lt;/p&gt;
&lt;h2 class=&#034;spip&#034;&gt;Immunit&#233; au bruit et d&#233;termination des r&#233;sistances&lt;/h2&gt;
&lt;p&gt;Les essais avec un seul poussoir ont employ&#233; une r&#233;sistance de 10k&#937; travers&#233;e par une courant de 0,5mA quand le poussoir est press&#233;. Avec de longs fils entre les poussoirs et l'Arduino, le bruit &#233;lectrique d&#251; aux ondes &#233;lectromagn&#233;tiques qui nous environnent peut &#234;tre important. Il est pr&#233;f&#233;rable d'utiliser des r&#233;sistances de plus faible valeur afin que le courant circulant dans le circuit quand un poussoir est press&#233; soit plus &#233;lev&#233; et que le bruit puisse &#234;tre absorb&#233; par l'alimentation. Nous allons donc choisir un courant maximum d'environ 15mA, soit une r&#233;sistance de 330&#937; &#224; la place de la r&#233;sistance de 10k&#937; utilis&#233;e jusqu'&#224; pr&#233;sent.&lt;/p&gt;
&lt;p&gt;Il faut maintenant d&#233;terminer les valeurs des r&#233;sistances R1 &#224; R7 pour obtenir les tensions que nous avons d&#233;termin&#233;es. Les diviseurs de tension pour chacun des poussoirs sont les suivants.&lt;/p&gt;
&lt;div class='spip_document_263 spip_document spip_documents spip_document_image spip_documents_center spip_document_center spip_document_avec_legende' data-legende-len=&#034;53&#034; data-legende-lenx=&#034;x&#034;
&gt;
&lt;figure class=&#034;spip_doc_inner&#034;&gt; &lt;img src='https://modelleisenbahn.triskell.org/local/cache-vignettes/L341xH417/diviseurs-2-d22db.png?1692301737' width='341' height='417' alt='' /&gt;
&lt;figcaption class='spip_doc_legende'&gt; &lt;div class='spip_doc_titre crayon document-titre-263 '&gt;&lt;strong&gt;Les diviseurs de tension pour chacun des poussoirs.
&lt;/strong&gt;&lt;/div&gt; &lt;/figcaption&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;p&gt;Par calcul on d&#233;termine les valeurs des r&#233;sistances pour chaque poussoir. La colonne &lt;i&gt;R&#233;sistance&lt;/i&gt; donne la r&#233;sistance qui serait n&#233;cessaire, la colonne &lt;i&gt;R&#233;sistance approch&#233;e&lt;/i&gt; donne la valeur standard employ&#233;e et la colonne &lt;i&gt;Tension approch&#233;e&lt;/i&gt; donne la tension effectivement obtenue en supposant &#233;videmment que la r&#233;sistance est juste.&lt;/p&gt;
&lt;table class=&#034;table spip&#034;&gt;
&lt;tbody&gt;
&lt;tr class='row_odd odd'&gt;
&lt;td&gt; &lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Tension&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;R&#233;sistance&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;R&#233;sistance approch&#233;e&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Tension approch&#233;e&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Erreur&lt;/strong&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr class='row_even even'&gt;
&lt;td&gt;R1&lt;/td&gt;
&lt;td&gt;0,625V&lt;/td&gt;
&lt;td&gt;47,14&#937;&lt;/td&gt;
&lt;td&gt;47&#937;&lt;/td&gt;
&lt;td&gt;0,634V&lt;/td&gt;
&lt;td&gt;0,04%&lt;/td&gt;&lt;/tr&gt;
&lt;tr class='row_odd odd'&gt;
&lt;td&gt;R2&lt;/td&gt;
&lt;td&gt;1,25V&lt;/td&gt;
&lt;td&gt;62,85&#937;&lt;/td&gt;
&lt;td&gt;62&#937;&lt;/td&gt;
&lt;td&gt;1,27V&lt;/td&gt;
&lt;td&gt;0,23%&lt;/td&gt;&lt;/tr&gt;
&lt;tr class='row_even even'&gt;
&lt;td&gt;R3&lt;/td&gt;
&lt;td&gt;1,875V&lt;/td&gt;
&lt;td&gt;88&#937;&lt;/td&gt;
&lt;td&gt;82&#937;&lt;/td&gt;
&lt;td&gt;1,89V&lt;/td&gt;
&lt;td&gt;1,34%&lt;/td&gt;&lt;/tr&gt;
&lt;tr class='row_odd odd'&gt;
&lt;td&gt;R4&lt;/td&gt;
&lt;td&gt;2,5V&lt;/td&gt;
&lt;td&gt;132&#937;&lt;/td&gt;
&lt;td&gt;130&#937;&lt;/td&gt;
&lt;td&gt;2,53V&lt;/td&gt;
&lt;td&gt;1,38%&lt;/td&gt;&lt;/tr&gt;
&lt;tr class='row_even even'&gt;
&lt;td&gt;R5&lt;/td&gt;
&lt;td&gt;3,125V&lt;/td&gt;
&lt;td&gt;220&#937;&lt;/td&gt;
&lt;td&gt;220&#937;&lt;/td&gt;
&lt;td&gt;3,17V&lt;/td&gt;
&lt;td&gt;1,03%&lt;/td&gt;&lt;/tr&gt;
&lt;tr class='row_odd odd'&gt;
&lt;td&gt;R6&lt;/td&gt;
&lt;td&gt;3,75V&lt;/td&gt;
&lt;td&gt;440&#937;&lt;/td&gt;
&lt;td&gt;430&#937;&lt;/td&gt;
&lt;td&gt;3,76V&lt;/td&gt;
&lt;td&gt;1,46%&lt;/td&gt;&lt;/tr&gt;
&lt;tr class='row_even even'&gt;
&lt;td&gt;R7&lt;/td&gt;
&lt;td&gt;4,375V&lt;/td&gt;
&lt;td&gt;1320&#937;&lt;/td&gt;
&lt;td&gt;1300&#937;&lt;/td&gt;
&lt;td&gt;4,377V&lt;/td&gt;
&lt;td&gt;1,50%&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;h2 class=&#034;spip&#034;&gt;Le retour du rebond&lt;/h2&gt;
&lt;p&gt;Il ne s'agit pas tout &#224; fait d'un rebond mais il va falloir prendre en compte ce que l'on appelle une transitoire.&lt;/p&gt;
&lt;p&gt;Quand l'un des poussoirs est press&#233;, l'entr&#233;e analogique passe de 5V &#224; la tension correspondante telle qu'elle a &#233;t&#233; r&#233;gl&#233;e par les r&#233;sistances. Mais elle ne le fait pas instantan&#233;ment. Cela prend un certain temps.&lt;/p&gt;
&lt;p&gt;Imaginons maintenant que le convertisseur analogique-num&#233;rique de l'Arduino capture la tension &lt;i&gt;alors que celle-ci est en train de descendre&lt;/i&gt;. Le r&#233;sultat va &#234;tre que le logiciel croit voir une pression sur un poussoir de rang sup&#233;rieur &#224; celui v&#233;ritablement press&#233;. De m&#234;me quand le poussoir va &#234;tre rel&#226;ch&#233;, la capture de la tension peut avoir lieu &lt;i&gt;alors qu'elle est en train de monter&lt;/i&gt; et retourner &#233;galement un num&#233;ro de poussoir de rang sup&#233;rieur. Il faut donc filtrer ces transitoires et n'accepter la valeur brute calcul&#233;e dans &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;numPoussoir&lt;/code&gt; que sous certaines conditions.&lt;/p&gt;
&lt;p&gt;Avec un seul poussoir ce ph&#233;nom&#232;ne n'existait pas car il n'y avait pas d'autre poussoir.&lt;/p&gt;
&lt;p&gt;Pour filtrer les valeurs non voulues, nous allons mettre en &#339;uvre ce que l'on appelle un &lt;i&gt;syst&#232;me s&#233;quentiel&lt;/i&gt;. On repr&#233;sente ce genre de syst&#232;me par un graphe, appel&#233; automate. Un ovale est un &lt;i&gt;&#233;tat&lt;/i&gt;, une fl&#232;che est une &lt;i&gt;transition&lt;/i&gt; qui permet de passer d'un &#233;tat &#224; l'autre. Les textes en vert sont des &lt;i&gt;conditions&lt;/i&gt; qui permettent ou emp&#234;chent une transition et les textes en rouge des &lt;i&gt;actions&lt;/i&gt; qui sont effectu&#233;es lors d'une transition. L'ovale &#224; double bordure est l'&lt;i&gt;&#233;tat initial&lt;/i&gt;. La fl&#232;che qui vient de nulle part et qui pointe sur l'&#233;tat initial correspond aux actions d'initialisation.&lt;/p&gt;
&lt;p&gt;Voici l'automate de notre syst&#232;me.&lt;/p&gt;
&lt;div class='spip_document_326 spip_document spip_documents spip_document_image spip_documents_center spip_document_center spip_document_avec_legende' data-legende-len=&#034;414&#034; data-legende-lenx=&#034;xxxx&#034;
&gt;
&lt;figure class=&#034;spip_doc_inner&#034;&gt; &lt;img src='https://modelleisenbahn.triskell.org/local/cache-vignettes/L500xH372/automate-2-76f26.png?1692301737' width='500' height='372' alt='' /&gt;
&lt;figcaption class='spip_doc_legende'&gt; &lt;div class='spip_doc_titre crayon document-titre-326 '&gt;&lt;strong&gt;Automate de lecture de l'&#233;tat des poussoirs
&lt;/strong&gt;&lt;/div&gt; &lt;div class='spip_doc_descriptif crayon document-descriptif-326 '&gt;Entre chaque transition, le temps n&#233;cessaire &#224; l'ex&#233;cution de &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;loop()&lt;/code&gt;, s'&#233;coule.&lt;br class='autobr' /&gt;
Le passage par l'&#233;tat ENFONCE permet de laisser passer du temps entre la d&#233;tection de la pression sur un poussoir et la lecture du num&#233;ro correspondant. Ce num&#233;ro n'est pas r&#233;actualis&#233; dans l'&#233;tat PRESSE, ce qui permet de filtrer les valeurs non d&#233;sir&#233;es lors du rel&#226;chement du poussoir.
&lt;/div&gt; &lt;/figcaption&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;p&gt;&#192; partir de l'&#233;tat initial, NON_PRESSE, qui correspond &#224; aucun poussoir enfonc&#233;, on peut :&lt;/p&gt;
&lt;ul class=&#034;spip&#034; role=&#034;list&#034;&gt;&lt;li&gt; rester dans cet &#233;tat (aucun poussoir enfonc&#233; correspond &#224; un num&#233;ro de poussoir &#233;gal &#224; 8) ;&lt;/li&gt;&lt;li&gt; passer dans l'&#233;tat ENFONCE (l'un des poussoir enfonc&#233; correspond &#224; un num&#233;ro de poussoir inf&#233;rieur &#224; 8).&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;Une fois dans l'&#233;tat ENFONCE :&lt;/p&gt;
&lt;ul class=&#034;spip&#034; role=&#034;list&#034;&gt;&lt;li&gt; soit le poussoir est rel&#226;ch&#233; imm&#233;diatement (c'est &#224; dire en quelques millisecondes, il s'agissait d'un rebond ou d'un parasite), le num&#233;ro de poussoir est &#233;gal &#224; 8 ;&lt;/li&gt;&lt;li&gt; soit il est toujours enfonc&#233;, num&#233;ro de poussoir inf&#233;rieur &#224; 8 et on confirme en passant dans l'&#233;tat PRESSE et en m&#233;morisant dans &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;etatBouton&lt;/code&gt; le num&#233;ro du poussoir enfonc&#233;.&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;Dans l'&#233;tat PRESSE :&lt;/p&gt;
&lt;ul class=&#034;spip&#034; role=&#034;list&#034;&gt;&lt;li&gt; soit le poussoir est maintenu enfonc&#233; (numPoussoir &lt; 8) et on attend en restant dans l'&#233;tat PRESSE ;&lt;/li&gt;&lt;li&gt; soit le poussoir est rel&#226;ch&#233; (numPoussoir == 8) et on repasse dans l'&#233;tat NON_PRESSE en remettant &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;etatBouton&lt;/code&gt; &#224; -1.&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;Le passage de l'automate &#224; un programme C est direct. On va avoir besoin d'une variable pour stocker l'&#233;tat dans lequel se trouve l'automate ainsi que des variables employ&#233;es par l'automate. Comme il est impossible de d&#233;tecter plusieurs poussoirs enfonc&#233;s, il est inutile d'avoir une variable d'&#233;tat par poussoir. Une seule variable suffit mais elle a autant d'&#233;tats que de poussoirs plus une pour repr&#233;senter le fait qu'aucun poussoir n'est enfonc&#233;.&lt;/p&gt;
&lt;div class=&#034;precode&#034;&gt;&lt;pre data-raccourci=&#034;code&#034; data-language=&#034;C&#034; class='spip_code spip_code_block language-C' dir='ltr' style='text-align:left;'&gt;&lt;code&gt;const byte NON_PRESSE = 0; const byte ENFONCE = 1; const byte PRESSE = 2; byte etatAutomate = NON_PRESSE; int etatPoussoir = -1; /* aucun poussoir n'est press&#233; au d&#233;but */ const int pinPoussoirs = 0; int lirePoussoirs() { int resultat; int numPoussoir = (analogRead(pinPoussoirs) + 64) / 128; int nouvelEtatPoussoir = etatPoussoir; /* &#224; priori rien ne change */ switch (etatAutomate) { case NON_PRESSE: if (numPoussoir &lt; 8) etatAutomate = ENFONCE; break; case ENFONCE: if (numPoussoir &lt; 8) { etatAutomate = PRESSE; nouvelEtatPoussoir = numPoussoir; } else { etatAutomate = NON_PRESSE; } break; case PRESSE: if (numPoussoir == 8) { etatAutomate = NON_PRESSE; nouvelEtatPoussoir = -1; } break; } return nouvelEtatPoussoir; }&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Il reste &#224; modifier &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;lireEvenement(...)&lt;/code&gt; pour l'adapter &#224; &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;lirePoussoirs()&lt;/code&gt;. En effet, en plus de l'information de pr&#233;sence d'&#233;v&#233;nement, il est n&#233;cessaire d'obtenir le num&#233;ro du poussoir qui a d&#233;clench&#233; l'&#233;v&#233;nement. Or une fonction C ne retourne qu'une seule valeur. Il faut donc trouver un moyen pour obtenir la seconde valeur, le num&#233;ro du poussoir.&lt;/p&gt;
&lt;p&gt;Nous allons employer un argument. En C les arguments sont pass&#233;s aux fonctions par valeur. C'est &#224; dire que la valeur contenue dans la variable que l'on passe &#224; la fonction est recopi&#233;e dans une variable locale de la fonction. Si la fonction change le contenu de cette variable, seule sa copie est chang&#233;e. Il faut donc employer un autre moyen pour que la fonction puisse modifier la variable qui lui est pass&#233;e. Ce moyen, ce sont les pointeurs.&lt;/p&gt;
&lt;p&gt;Une variable est plac&#233;e dans la m&#233;moire RAM du micro-contr&#244;leur. On peut voir la RAM comme un tableau de cases. Chaque case a un num&#233;ro, on dit une &lt;i&gt;adresse&lt;/i&gt;. Il est possible d'obtenir l'adresse d'une variable via l'op&#233;rateur &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;&amp;&lt;/code&gt;, de d&#233;finir une variable qui soit un pointeur vers un type, via la notation &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;*&lt;/code&gt; et il est possible d'&#233;crire ou de lire dans une variable par l'interm&#233;diaire de son adresse via l'op&#233;rateur &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;*&lt;/code&gt;. Ainsi :&lt;/p&gt;
&lt;p&gt;&lt;code data-raccourci=&#034;code&#034; data-language=&#034;C&#034; class='spip_code spip_code_inline language-C' dir='ltr'&gt;int *p;&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;d&#233;finit un pointeur vers une variable de type int. Ce pointeur est pour l'instant non initialis&#233;, il ne pointe sur rien. Essayer d'acc&#233;der &#224; ce qu'il pointe est une erreur.&lt;/p&gt;
&lt;div class=&#034;precode&#034;&gt;&lt;pre data-raccourci=&#034;code&#034; data-language=&#034;C&#034; class='spip_code spip_code_block language-C' dir='ltr' style='text-align:left;'&gt;&lt;code&gt;int a; int *p = &amp;a;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;d&#233;finit un pointeur p vers une variable de type int qui pointe sur a. &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;&amp;a&lt;/code&gt; retourne l'adresse de a.&lt;/p&gt;
&lt;p&gt;&lt;code data-raccourci=&#034;code&#034; data-language=&#034;C&#034; class='spip_code spip_code_inline language-C' dir='ltr'&gt;*p = 3;&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;met la valeur 3 dans la variable a.&lt;/p&gt;
&lt;p&gt;Pour d&#233;finir la fonction &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;lireEvenement(...)&lt;/code&gt; qui retourne un byte et prend pour argument un pointeur vers un int, et qui modifie la variable point&#233;e, on &#233;crira.&lt;/p&gt;
&lt;div class=&#034;precode&#034;&gt;&lt;pre data-raccourci=&#034;code&#034; data-language=&#034;C&#034; class='spip_code spip_code_block language-C' dir='ltr' style='text-align:left;'&gt;&lt;code&gt;byte lireEvenement(int *numPoussoir) { byte evenement; int nouvelEtatPoussoir = lirePoussoirs(); if (nouvelEtatPoussoir == etatPoussoir) evenement = AUCUN_EVENEMENT; if (nouvelEtatPoussoir &gt;= 0 &amp;&amp; etatPoussoir == -1) evenement = EVENEMENT_PRESSE; if (nouvelEtatPoussoir == -1 &amp;&amp; etatPoussoir &gt;= 0) evenement = EVENEMENT_RELACHE; etatPoussoir = nouvelEtatPoussoir; *numPoussoir = etatPoussoir; return evenement; }&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;L'argument &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;int *numPoussoir&lt;/code&gt; d&#233;finit &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;numPoussoir&lt;/code&gt; qui est un pointeur sur un int. &#192; l'avant derni&#232;re ligne de la fonction, l'&#233;tat du poussoir est &#233;crit dans la variable point&#233;e par &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;numPoussoir&lt;/code&gt;, il s'agit de la ligne &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;*numPoussoir = etatPoussoir;&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Il faut donc que numPoussoir pointe sur la variable dans laquelle on d&#233;sire r&#233;cup&#233;rer le num&#233;ro de poussoir. Donc, pour appeler cette fonction, on &#233;crira.&lt;/p&gt;
&lt;div class=&#034;precode&#034;&gt;&lt;pre data-raccourci=&#034;code&#034; data-language=&#034;C&#034; class='spip_code spip_code_block language-C' dir='ltr' style='text-align:left;'&gt;&lt;code&gt; int numeroPoussoir; byte evenement = lireEvenement(&amp;numeroPoussoir);&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;ce qui a pour effet de passer &#224; la fonction l'adresse, op&#233;rateur &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;&amp;&lt;/code&gt;, de &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;numeroPoussoir&lt;/code&gt; afin d'obtenir la valeur d&#233;sir&#233;e dans cette variable.&lt;/p&gt;
&lt;h2 class=&#034;spip&#034;&gt;Essai du syst&#232;me&lt;/h2&gt;
&lt;p&gt;La premi&#232;re &#233;tape consiste &#224; c&#226;bler sur la &lt;i&gt;breadboard&lt;/i&gt; les poussoirs est les r&#233;sistances comme ceci.&lt;/p&gt;
&lt;div class='spip_document_267 spip_document spip_documents spip_document_image spip_documents_center spip_document_center spip_document_avec_legende' data-legende-len=&#034;44&#034; data-legende-lenx=&#034;x&#034;
&gt;
&lt;figure class=&#034;spip_doc_inner&#034;&gt; &lt;img src='https://modelleisenbahn.triskell.org/local/cache-vignettes/L500xH535/8_poussoirs_bb-2-28461.png?1692301737' width='500' height='535' alt='' /&gt;
&lt;figcaption class='spip_doc_legende'&gt; &lt;div class='spip_doc_titre crayon document-titre-267 '&gt;&lt;strong&gt;Placement des composants sur le breadboard
&lt;/strong&gt;&lt;/div&gt; &lt;/figcaption&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;p&gt;Voici le programme complet de test du syst&#232;me. Les messages d'appui ou de rel&#226;chement des poussoirs sont affich&#233;s sur le moniteur s&#233;rie avec le num&#233;ro de poussoir enfonc&#233;.&lt;/p&gt;
&lt;div class=&#034;precode&#034;&gt;&lt;pre data-raccourci=&#034;code&#034; data-language=&#034;C&#034; class='spip_code spip_code_block language-C' dir='ltr' style='text-align:left;'&gt;&lt;code&gt; const byte NON_PRESSE = 0; const byte ENFONCE = 1; const byte PRESSE = 2; byte etatAutomate = NON_PRESSE; int etatPoussoir = -1; const byte AUCUN_EVENEMENT = 0; const byte EVENEMENT_PRESSE = 1; const byte EVENEMENT_RELACHE = 2; const int pinPoussoirs = 0; int lirePoussoirs() { int resultat; int numPoussoir = (analogRead(pinPoussoirs) + 64) / 128; int nouvelEtatPoussoir = etatPoussoir; /* &#224; priori rien ne change */ switch (etatAutomate) { case NON_PRESSE: if (numPoussoir &lt; 8) etatAutomate = ENFONCE; break; case ENFONCE: if (numPoussoir &lt; 8) { etatAutomate = PRESSE; nouvelEtatPoussoir = numPoussoir; } else { etatAutomate = NON_PRESSE; } break; case PRESSE: if (numPoussoir == 8) { etatAutomate = NON_PRESSE; nouvelEtatPoussoir = -1; } break; } return nouvelEtatPoussoir; } /* * construction d'un &#233;v&#233;nement en comparant * le nouvel &#233;tat des poussoirs avec l'&#233;tat pr&#233;c&#233;dent. */ byte lireEvenement(int *numPoussoir) { byte evenement; int nouvelEtatPoussoir = lirePoussoirs(); if (nouvelEtatPoussoir == etatPoussoir) evenement = AUCUN_EVENEMENT; if (nouvelEtatPoussoir &gt;= 0 &amp;&amp; etatPoussoir == -1) evenement = EVENEMENT_PRESSE; if (nouvelEtatPoussoir == -1 &amp;&amp; etatPoussoir &gt;= 0) evenement = EVENEMENT_RELACHE; if (evenement == EVENEMENT_PRESSE) { *numPoussoir = nouvelEtatPoussoir; } else if (evenement == EVENEMENT_RELACHE) { *numPoussoir = etatPoussoir; } etatPoussoir = nouvelEtatPoussoir; return evenement; } void setup() { Serial.begin(9600); } void loop() { int numPoussoir; byte evenement = lireEvenement(&amp;numPoussoir); switch (evenement) { case EVENEMENT_PRESSE: Serial.print(&#034;Presse : &#034;); Serial.println(numPoussoir); break; case EVENEMENT_RELACHE: Serial.print(&#034;Relache : &#034;); Serial.println(numPoussoir); break; } delay(3); }&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Une petite vid&#233;o montrant la mise en &#339;uvre du programme.&lt;/p&gt;
&lt;div class=&#034;spip_document_268 spip_document spip_documents spip_document_video&#034;&gt;
&lt;figure class=&#034;spip_doc_inner&#034;&gt;
&lt;div class=&#034;video-intrinsic-wrapper&#034; style='height:0;width:640px;max-width:100%;padding-bottom:56.25%;position:relative;'&gt; &lt;div class=&#034;video-wrapper&#034; style=&#034;position: absolute;top:0;left:0;width:100%;height:100%;&#034;&gt; &lt;video class=&#034;mejs mejs-268&#034; data-id=&#034;9d2ceb7dd5caaba544f271e115ddf616&#034; data-mejsoptions='{&#034;iconSprite&#034;: &#034;plugins-dist/medias/lib/mejs/mejs-controls.svg&#034;,&#034;alwaysShowControls&#034;: true,&#034;pluginPath&#034;:&#034;plugins-dist/medias/lib/mejs/&#034;,&#034;loop&#034;:false,&#034;videoWidth&#034;:&#034;100%&#034;,&#034;videoHeight&#034;:&#034;100%&#034;}' width=&#034;100%&#034; height=&#034;100%&#034; controls=&#034;controls&#034; preload=&#034;none&#034; &gt; &lt;source type=&#034;application/x-shockwave-flash&#034; src=&#034;http://www.youtube.com/v/qNStYgPLN6E?hl=fr_FR&amp;version=3&amp;rel=0&#034; /&gt; &lt;img src='https://modelleisenbahn.triskell.org/local/cache-vignettes/L64xH64/swf-d2c4d-75a7b.svg?1772798901' width='64' height='64' alt='Impossible de lire la video' /&gt; &lt;/video&gt; &lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#034;base64javascript20209960069f2c6729ef848.51775611&#034; title=&#034;PHNjcmlwdD4gdmFyIG1lanNwYXRoPSdwbHVnaW5zLWRpc3QvbWVkaWFzL2xpYi9tZWpzL21lZGlhZWxlbWVudC1hbmQtcGxheWVyLm1pbi5qcz8xNzcyNzk1ODQwJyxtZWpzY3NzPSdwbHVnaW5zLWRpc3QvbWVkaWFzL2xpYi9tZWpzL21lZGlhZWxlbWVudHBsYXllci5taW4uY3NzPzE3NzI3OTU4NDAnOwp2YXIgbWVqc2xvYWRlcjsKKGZ1bmN0aW9uKCl7dmFyIGE9bWVqc2xvYWRlcjsidW5kZWZpbmVkIj09dHlwZW9mIGEmJihtZWpzbG9hZGVyPWE9e2dzOm51bGwscGx1Zzp7fSxjc3M6e30saW5pdDpudWxsLGM6MCxjc3Nsb2FkOm51bGx9KTthLmluaXR8fChhLmNzc2xvYWQ9ZnVuY3Rpb24oYyl7aWYoInVuZGVmaW5lZCI9PXR5cGVvZiBhLmNzc1tjXSl7YS5jc3NbY109ITA7dmFyIGI9ZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgibGluayIpO2IuaHJlZj1jO2IucmVsPSJzdHlsZXNoZWV0IjtiLnR5cGU9InRleHQvY3NzIjtkb2N1bWVudC5nZXRFbGVtZW50c0J5VGFnTmFtZSgiaGVhZCIpWzBdLmFwcGVuZENoaWxkKGIpfX0sYS5pbml0PWZ1bmN0aW9uKCl7ITA9PT1hLmdzJiZmdW5jdGlvbihjKXtqUXVlcnkoImF1ZGlvLm1lanMsdmlkZW8ubWVqcyIpLm5vdCgiLmRvbmUsLm1lanNfX3BsYXllciIpLmVhY2goZnVuY3Rpb24oKXtmdW5jdGlvbiBiKCl7dmFyIGU9ITAsaDtmb3IoaCBpbiBkLmNzcylhLmNzc2xvYWQoZC5jc3NbaF0pO2Zvcih2YXIgZiBpbiBkLnBsdWdpbnMpInVuZGVmaW5lZCI9PQp0eXBlb2YgYS5wbHVnW2ZdPyhlPSExLGEucGx1Z1tmXT0hMSxqUXVlcnkuZ2V0U2NyaXB0KGQucGx1Z2luc1tmXSxmdW5jdGlvbigpe2EucGx1Z1tmXT0hMDtiKCl9KSk6MD09YS5wbHVnW2ZdJiYoZT0hMSk7ZSYmalF1ZXJ5KCIjIitjKS5tZWRpYWVsZW1lbnRwbGF5ZXIoalF1ZXJ5LmV4dGVuZChkLm9wdGlvbnMse3N1Y2Nlc3M6ZnVuY3Rpb24oYSxjKXtmdW5jdGlvbiBiKCl7dmFyIGI9alF1ZXJ5KGEpLmNsb3Nlc3QoIi5tZWpzX19pbm5lciIpO2EucGF1c2VkPyhiLmFkZENsYXNzKCJwYXVzaW5nIiksc2V0VGltZW91dChmdW5jdGlvbigpe2IuZmlsdGVyKCIucGF1c2luZyIpLnJlbW92ZUNsYXNzKCJwbGF5aW5nIikucmVtb3ZlQ2xhc3MoInBhdXNpbmciKS5hZGRDbGFzcygicGF1c2VkIil9LDEwMCkpOmIucmVtb3ZlQ2xhc3MoInBhdXNlZCIpLnJlbW92ZUNsYXNzKCJwYXVzaW5nIikuYWRkQ2xhc3MoInBsYXlpbmciKX1iKCk7YS5hZGRFdmVudExpc3RlbmVyKCJwbGF5IixiLCExKTsKYS5hZGRFdmVudExpc3RlbmVyKCJwbGF5aW5nIixiLCExKTthLmFkZEV2ZW50TGlzdGVuZXIoInBhdXNlIixiLCExKTthLmFkZEV2ZW50TGlzdGVuZXIoInBhdXNlZCIsYiwhMSk7Zy5hdHRyKCJhdXRvcGxheSIpJiZhLnBsYXkoKX19KSl9dmFyIGc9alF1ZXJ5KHRoaXMpLmFkZENsYXNzKCJkb25lIiksYzsoYz1nLmF0dHIoImlkIikpfHwoYz0ibWVqcy0iK2cuYXR0cigiZGF0YS1pZCIpKyItIithLmMrKyxnLmF0dHIoImlkIixjKSk7dmFyIGQ9e29wdGlvbnM6e30scGx1Z2luczp7fSxjc3M6W119LGUsaDtmb3IoZSBpbiBkKWlmKGg9Zy5hdHRyKCJkYXRhLW1lanMiK2UpKWRbZV09alF1ZXJ5LnBhcnNlSlNPTihoKTtiKCl9KX0oalF1ZXJ5KX0pO2EuZ3N8fCgidW5kZWZpbmVkIiE9PXR5cGVvZiBtZWpzY3NzJiZhLmNzc2xvYWQobWVqc2NzcyksYS5ncz1qUXVlcnkuZ2V0U2NyaXB0KG1lanNwYXRoLGZ1bmN0aW9uKCl7YS5ncz0hMDthLmluaXQoKTtqUXVlcnkoYS5pbml0KTtvbkFqYXhMb2FkKGEuaW5pdCl9KSl9KSgpOzwvc2NyaXB0Pg==&#034;&gt;&lt;/div&gt; &lt;/figure&gt;
&lt;/div&gt;
&lt;p&gt;Le syst&#232;me de commande &#224; 8 boutons sur une entr&#233;e analogique est op&#233;rationnel.&lt;/p&gt;
&lt;p&gt;Nous avons vu quelques &#233;l&#233;ments suppl&#233;mentaires de langage C comme les pointeurs et leur emploi pour retourner plusieurs valeurs &#224; partir d'une fonction. Nous avons vu rapidement les automates et comment les mettre en &#339;uvre avec un &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;switch ... case&lt;/code&gt;. La prochaine fois nous ajouterons nos 8 servo-moteurs.&lt;/p&gt;&lt;/div&gt;
		
		</content:encoded>


		

	</item>
<item xml:lang="fr">
		<title>Commande du servo-moteur par bouton poussoir</title>
		<link>https://modelleisenbahn.triskell.org/spip.php?article58</link>
		<guid isPermaLink="true">https://modelleisenbahn.triskell.org/spip.php?article58</guid>
		<dc:date>2013-11-11T17:57:57Z</dc:date>
		<dc:format>text/html</dc:format>
		<dc:language>fr</dc:language>
		<dc:creator>Jean-Luc</dc:creator>


		<dc:subject>aiguille</dc:subject>
		<dc:subject>servo</dc:subject>
		<dc:subject>Arduino</dc:subject>

		<description>
&lt;p&gt;Nous allons maintenant ajouter un bouton poussoir pour commander le mouvement du servo-moteur. Cet article fait suite &#224; &#171; Mise en &#339;uvre d'un servo-moteur &#187;. &lt;br class='autobr' /&gt;
Le syst&#232;me fonctionnera de la mani&#232;re suivante : Lorsque le servo-moteur est dans une des positions extr&#234;mes, une pression sur le poussoir donnera au servo-moteur une vitesse lui permettant de gagner l'autre position extr&#234;me. Lorsque le servo-moteur est en mouvement, une pression sur le bouton inversera la vitesse. &lt;br class='autobr' /&gt;
Mise en &#339;uvre du (&#8230;)&lt;/p&gt;


-
&lt;a href="https://modelleisenbahn.triskell.org/spip.php?rubrique22" rel="directory"&gt;Man&#339;uvre des aiguilles avec des servo-moteurs&lt;/a&gt;

/ 
&lt;a href="https://modelleisenbahn.triskell.org/spip.php?mot4" rel="tag"&gt;aiguille&lt;/a&gt;, 
&lt;a href="https://modelleisenbahn.triskell.org/spip.php?mot5" rel="tag"&gt;servo&lt;/a&gt;, 
&lt;a href="https://modelleisenbahn.triskell.org/spip.php?mot10" rel="tag"&gt;Arduino&lt;/a&gt;

		</description>


 <content:encoded>&lt;div class='rss_texte'&gt;&lt;p&gt;Nous allons maintenant ajouter un bouton poussoir pour commander le mouvement du servo-moteur. Cet article fait suite &#224; &#171; &lt;a href='https://modelleisenbahn.triskell.org/spip.php?article57' class=&#034;spip_in&#034;&gt;Mise en &#339;uvre d'un servo-moteur&lt;/a&gt; &#187;.&lt;/p&gt;
&lt;p&gt;Le syst&#232;me fonctionnera de la mani&#232;re suivante : Lorsque le servo-moteur est dans une des positions extr&#234;mes, une pression sur le poussoir donnera au servo-moteur une vitesse lui permettant de gagner l'autre position extr&#234;me. Lorsque le servo-moteur est en mouvement, une pression sur le bouton inversera la vitesse.&lt;/p&gt;
&lt;h2 class=&#034;spip&#034;&gt;Mise en &#339;uvre du bouton poussoir&lt;/h2&gt;
&lt;p&gt;Comme d&#233;j&#224; expliqu&#233;, nous allons r&#233;server les entr&#233;es/sorties num&#233;riques, les broches 0 &#224; 13 de l'Arduino, au pilotage des servo-moteurs et &#224; l'allumage des LED t&#233;moin.&lt;/p&gt;
&lt;p&gt;Pour l'instant, l'unique bouton poussoir est connect&#233; sur une entr&#233;e analogique, A0 par exemple. Une entr&#233;e analogique permet &#224; l'Arduino de lire une grandeur analogique, entre 0V et 5V, et de la convertir en un nombre que l'on pourra manipuler dans le programme. Le nombre obtenu peut prendre des valeurs comprises entre 0 (pour 0V) et 1023 (pour 5V) avec donc 1024 valeurs possibles.&lt;/p&gt;
&lt;p&gt;Pour notre bouton, il n'y aura que deux valeurs, celle qui correspond au bouton rel&#226;ch&#233; et celle qui correspond au bouton enfonc&#233;. Le bouton est connect&#233; &#224; l'Arduino comme ceci.&lt;/p&gt;
&lt;div class='spip_document_248 spip_document spip_documents spip_document_image spip_documents_center spip_document_center spip_document_avec_legende' data-legende-len=&#034;46&#034; data-legende-lenx=&#034;x&#034;
&gt;
&lt;figure class=&#034;spip_doc_inner&#034;&gt; &lt;img src='https://modelleisenbahn.triskell.org/local/cache-vignettes/L490xH558/poussoir-24990.png?1692208044' width='490' height='558' alt='' /&gt;
&lt;figcaption class='spip_doc_legende'&gt; &lt;div class='spip_doc_titre crayon document-titre-248 '&gt;&lt;strong&gt;Connexion du bouton poussoir &#224; l'Arduino Uno
&lt;/strong&gt;&lt;/div&gt; &lt;/figcaption&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;p&gt;Lorsque le bouton est rel&#226;ch&#233;, l'entr&#233;e analogique A0 est tir&#233;e &#224; 0V via la r&#233;sistance de 10k&#937;. Lorsque le bouton est press&#233;, l'entr&#233;e est mise &#224; 5V.&lt;/p&gt;
&lt;p&gt;Du c&#244;t&#233; du programme, nous allons s&#233;parer l'espace de valeurs (0 &#224; 1023) en deux parties &#233;gales : les valeurs inf&#233;rieures ou &#233;gales &#224; 511 et celles sup&#233;rieures &#224; 511 et nous allons d&#233;finir une fonction qui lit la valeur analogique, la compare &#224; la valeur milieu et retourne soit &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;RELACHE&lt;/code&gt;, soit &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;PRESSE&lt;/code&gt;. Ces deux constantes sont des bool&#233;ens, c'est &#224; dire des valeurs logiques. Elle sont d&#233;finies pour faciliter la lecture du programme. Jusqu'alors nous n'avons vu que des fonctions qui ne retournaient rien, c'est &#224; dire &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;void&lt;/code&gt;. Ici la fonction &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;lireBouton&lt;/code&gt; retourne un bool&#233;en, qui sera l'&#233;tat du bouton. Nous avons donc le morceau de programme suivant avec la d&#233;finition des constantes n&#233;cessaires et la fonction de lecture de l'&#233;tat du bouton poussoir.&lt;/p&gt;
&lt;div class=&#034;precode&#034;&gt;&lt;pre data-raccourci=&#034;code&#034; data-language=&#034;C&#034; class='spip_code spip_code_block language-C' dir='ltr' style='text-align:left;'&gt;&lt;code&gt;/* le bouton est connect&#233; &#224; la broche A0 */ const int pinBouton = 0; /* valeur logique pour indiquer que le bouton est press&#233; */ const boolean PRESSE = true; /* valeur logique pour indiquer que le bouton est rel&#226;ch&#233; */ const boolean RELACHE = false; /* * lecture du bouton poussoir. Le bouton poussoir est connect&#233; * sur une entr&#233;e analogique. Quand il est press&#233;, l'entr&#233;e est * connect&#233;e au +5V. Quand il est relach&#233;, l'entr&#233;e est connect&#233;e * &#224; la masse. On va discriminer les deux &#233;tats en comparant la * valeur analogique lue &#224; 511 qui est la valeur milieu. */ boolean lirePoussoir() { boolean resultat = RELACHE; if (analogRead(pinBouton) &gt; 511) { resultat = PRESSE; } /* retourne l'&#233;tat */ return resultat; }&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Mais l'&#233;tat du bouton ne nous int&#233;resse pas directement. En effet, ne mettre le servo-moteur en mouvement que lorsque le bouton est press&#233; forcerait l'utilisateur &#224; maintenir le bouton press&#233; pendant le mouvement. Ce sont donc les changements d'&#233;tat du bouton qui nous int&#233;ressent : le fait de passer de l'&#233;tat &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;RELACHE&lt;/code&gt; &#224; l'&#233;tat &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;PRESSE&lt;/code&gt; ou le fait de passer de l'&#233;tat &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;PRESSE&lt;/code&gt; &#224; l'&#233;tat &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;RELACHE&lt;/code&gt;. Pour d&#233;tecter ces changements d'&#233;tat, il faut m&#233;moriser l'&#233;tat pr&#233;c&#233;dent du bouton et, quand on lit son &#233;tat actuel, le compar&#233; &#224; l'&#233;tat pr&#233;c&#233;dent pour d&#233;terminer si l'un des changements a eu lieu. On a donc besoin d'une variable pour y m&#233;moriser l'&#233;tat pr&#233;c&#233;dent. Pour clarifier les choses et rendre le programme lisible, nous allons aussi d&#233;finir 3 constantes : &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;AUCUN_EVENEMENT&lt;/code&gt;, l'&#233;tat pr&#233;c&#233;dent du bouton est identique &#224; l'&#233;tat courant, &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;EVENEMENT_PRESSE&lt;/code&gt;, l'&#233;tat pr&#233;c&#233;dent du bouton &#233;tait &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;RELACHE&lt;/code&gt;, l'&#233;tat courant est &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;PRESSE&lt;/code&gt; et &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;EVENEMENT_RELACHE&lt;/code&gt;, l'&#233;tat pr&#233;c&#233;dent du bouton &#233;tait &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;PRESSE&lt;/code&gt;, l'&#233;tat courant est &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;RELACHE&lt;/code&gt;. Ces constantes sont des &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;byte&lt;/code&gt;, c'est &#224; dire un type de donn&#233;e pouvant prendre 256 valeurs diff&#233;rentes, ce qui suffit amplement.&lt;/p&gt;
&lt;div class=&#034;precode&#034;&gt;&lt;pre data-raccourci=&#034;code&#034; data-language=&#034;C&#034; class='spip_code spip_code_block language-C' dir='ltr' style='text-align:left;'&gt;&lt;code&gt;const byte AUCUN_EVENEMENT = 0; const byte EVENEMENT_PRESSE = 1; const byte EVENEMENT_RELACHE = 2;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Enfin nous allons d&#233;finir la fonction &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;lireEvenement()&lt;/code&gt; qui va lire l'&#233;tat courant du bouton et calculer l'&#233;v&#233;nement. Le code vient assez naturellement.&lt;/p&gt;
&lt;div class=&#034;precode&#034;&gt;&lt;pre data-raccourci=&#034;code&#034; data-language=&#034;C&#034; class='spip_code spip_code_block language-C' dir='ltr' style='text-align:left;'&gt;&lt;code&gt;/* * construction d'un &#233;v&#233;nement. * - Si l'&#233;tat du bouton n'a pas chang&#233; entre l'&#233;tat pr&#233;c&#233;dent du bouton * et le nouvelle &#233;tat, l'&#233;v&#233;nement est AUCUN_EVENEMENT. * - Si le pouton &#233;tait pr&#233;c&#233;demment RELACHE et qu'il est maintenant PRESSE, * l'&#233;v&#233;nement est EVENEMENT_PRESSE. * - Si le pouton &#233;tait pr&#233;c&#233;demment PRESSE et qu'il est maintenant RELACHE, * l'&#233;v&#233;nement est EVENEMENT_RELACHE. */ byte lireEvenement() { byte evenement; /* lit l'&#233;tat courant du bouton */ boolean nouvelEtat = lirePoussoir(); /* calcule l'&#233;v&#233;nement */ if (nouvelEtat == etatBouton) evenement = AUCUN_EVENEMENT; if (nouvelEtat == PRESSE &amp;&amp; etatBouton == RELACHE) evenement = EVENEMENT_PRESSE; if (nouvelEtat == RELACHE &amp;&amp; etatBouton == PRESSE) evenement = EVENEMENT_RELACHE; /* L'&#233;tat courant devient l'&#233;tat pr&#233;c&#233;dent */ etatBouton = nouvelEtat; /* retourne l'&#233;v&#233;nement */ return evenement; }&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Afin de tester la lecture du poussoir ind&#233;pendamment, nous allons mettre en &#339;uvre l'envoi de message sur la ligne s&#233;rie qui, via l'USB, s'affiche dans le Moniteur S&#233;rie de l'environnement de programmation Arduino. Il faut tout d'abord ouvrir la connexion dans la fonction &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;setup()&lt;/code&gt; en utilisant la m&#233;thode &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;begin(...)&lt;/code&gt; de &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;Serial&lt;/code&gt;. Nous allons ensuite utiliser la m&#233;thode &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;println&lt;/code&gt; pour afficher un message sur le moniteur s&#233;rie. Voici le programme complet pour cette premi&#232;re application mettant en &#339;uvre un bouton.&lt;/p&gt;
&lt;div class=&#034;precode&#034;&gt;&lt;pre data-raccourci=&#034;code&#034; data-language=&#034;C&#034; class='spip_code spip_code_block language-C' dir='ltr' style='text-align:left;'&gt;&lt;code&gt;const int pinBouton = 0; /* le bouton est connect&#233; &#224; la broche A0 */ const boolean PRESSE = true; const boolean RELACHE = false; boolean etatBouton = RELACHE; const byte AUCUN_EVENEMENT = 0; const byte EVENEMENT_PRESSE = 1; const byte EVENEMENT_RELACHE = 2; boolean lirePoussoir() { boolean resultat = RELACHE; if (analogRead(pinBouton) &gt; 512) { resultat = PRESSE; } return resultat; } byte lireEvenement() { byte evenement; boolean nouvelEtat = lirePoussoir(); if (nouvelEtat == etatBouton) evenement = AUCUN_EVENEMENT; if (nouvelEtat == PRESSE &amp;&amp; etatBouton == RELACHE) evenement = EVENEMENT_PRESSE; if (nouvelEtat == RELACHE &amp;&amp; etatBouton == PRESSE) evenement = EVENEMENT_RELACHE; etatBouton = nouvelEtat; return evenement; } void setup() { Serial.begin(9600); } void loop() { byte evenement = lireEvenement(); if (evenement == EVENEMENT_PRESSE) Serial.println(&#034;presse !&#034;); if (evenement == EVENEMENT_RELACHE) Serial.println(&#034;relache !&#034;); }&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&#192; ma grande surprise ce programme fonctionne sans effort suppl&#233;mentaire ! &#192; ma grande surprise car lorsque l'on presse ou que l'on rel&#226;che un bouton, le contact ou la coupure ne s'effectue pas d'un coup et une succession rapide de contact-coupure a lieu. On appelle cela un rebond. Mon poussoir n'a pas de caract&#233;ristique particuli&#232;re et j'ai par ailleurs eu des rebonds en le connectant &#224; une entr&#233;e num&#233;rique. La r&#233;ponse &#224; ce myst&#232;re est donc ailleurs.&lt;/p&gt;
&lt;p&gt;Deux techniques sont possibles pour filtrer les rebonds des poussoirs :&lt;/p&gt;
&lt;ul class=&#034;spip&#034; role=&#034;list&#034;&gt;&lt;li&gt; par mat&#233;riel : un condensateur de filtrage ;&lt;/li&gt;&lt;li&gt; par logiciel : laisser passer du temps entre deux lectures.&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;Or, la conversion analogique num&#233;rique n'est pas instantan&#233;e. Entre deux conversions successives et donc deux acquisitions successive de la valeur analogique, il s'&#233;coule 100&#181;s. Ce qui &#233;quivaut &#224; la solution logicielle de &#171; laisser passer du temps entre 2 lectures &#187;. Cette dur&#233;e semble &#234;tre suffisante pour filtrer les rebonds de notre bouton.&lt;/p&gt;
&lt;h2 class=&#034;spip&#034;&gt;Int&#233;gration avec le programme de pilotage du servo-moteur&lt;/h2&gt;
&lt;p&gt;Nous allons maintenant int&#233;grer notre fonction de lecture d'&#233;v&#233;nement au programme de pilotage du servo-moteur tel que nous l'avons pr&#233;sent&#233; dans l'&lt;a href='https://modelleisenbahn.triskell.org/spip.php?article57' class=&#034;spip_in&#034;&gt;article pr&#233;c&#233;dent&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Il faut proc&#233;der &#224; quelques modification. Tout d'abord, il faut supprimer l'aller-retour qu'effectue le servo-moteur. Ensuite, il faut ajouter une variable qui va permettre de savoir dans quel &#233;tat se trouve le servo-moteur afin de prendre la d&#233;cision ad&#233;quate quand le bouton est press&#233;. On va distinguer 4 &#233;tats :&lt;/p&gt;
&lt;p&gt;&lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;SERVO_A_ANGLE_MIN&lt;/code&gt; : le servo-moteur est arr&#234;t&#233; dans la position correspondant &#224; l'angle minimum. Sa vitesse est &#233;gale &#224; 0.&lt;br/&gt;
&lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;SERVO_A_ANGLE_MAX&lt;/code&gt; : le servo-moteur est arr&#234;t&#233; dans la position correspondant &#224; l'angle maximum. Sa vitesse est &#233;gale &#224; 0.&lt;br/&gt;
&lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;SERVO_EN_MOUVEMENT_VERS_ANGLE_MAX&lt;/code&gt; : le servo est en mouvement vers la position d'angle maximum. Sa vitesse est &#233;gale &#224; 1.&lt;br/&gt;
&lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;SERVO_EN_MOUVEMENT_VERS_ANGLE_MIN&lt;/code&gt; : le servo est en mouvement vers la position d'angle minimum. Sa vitesse est &#233;gale &#224; -1.&lt;/p&gt;
&lt;p&gt;Comme tout est nombre, nous allons d&#233;finir chacune de ces constantes comme &#233;tant un &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;byte&lt;/code&gt; et d&#233;finir une variable &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;etatServo&lt;/code&gt; de type &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;byte&lt;/code&gt; comme ceci.&lt;/p&gt;
&lt;div class=&#034;precode&#034;&gt;&lt;pre data-raccourci=&#034;code&#034; data-language=&#034;C&#034; class='spip_code spip_code_block language-C' dir='ltr' style='text-align:left;'&gt;&lt;code&gt;const byte SERVO_A_ANGLE_MIN = 0; const byte SERVO_A_ANGLE_MAX = 1; const byte SERVO_EN_MOUVEMENT_VERS_ANGLE_MAX = 2; const byte SERVO_EN_MOUVEMENT_VERS_ANGLE_MIN = 3; const int angleMin = 1250; const int angleMax = 1750; Servo monServo; int vitesse = 0; int angle = angleMin; byte etatServo = SERVO_A_ANGLE_MIN;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Dans &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;setup()&lt;/code&gt;, nous retrouvons l'accrochage de &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;monServo&lt;/code&gt; &#224; la broche 2. La gestion du mouvement du servo est modifi&#233;e. Quand l'angle d&#233;passe l'angle maximum, il est recal&#233; comme auparavant. Mais dor&#233;navant la vitesse est mise &#224; 0 et l'&#233;tat du servo est chang&#233; en &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;SERVO_A_ANGLE_MAX&lt;/code&gt;. Quand l'angle d&#233;passe l'angle minimum, il est recal&#233; &#224; l'angle minimum, la vitesse est mise &#224; 0 et l'&#233;tat du servo est chang&#233; en &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;SERVO_A_ANGLE_MIN&lt;/code&gt;. De cette mani&#232;re, le servo arr&#234;te son mouvement quand il atteint l'une des positions extr&#234;mes.&lt;/p&gt;
&lt;p&gt;On va ensuite lire l'&#233;v&#233;nement. Si l'&#233;v&#233;nement est &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;EVENEMENT_PRESSE&lt;/code&gt;, on va effectuer les actions suivantes :&lt;/p&gt;
&lt;ul class=&#034;spip&#034; role=&#034;list&#034;&gt;&lt;li&gt; Si le servo est dans l'&#233;tat &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;SERVO_A_ANGLE_MIN&lt;/code&gt; ou&lt;br/&gt; &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;SERVO_EN_MOUVEMENT_VERS_ANGLE_MIN&lt;/code&gt;, la vitesse est mise &#224; 1 et l'&#233;tat du servo est chang&#233; en &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;SERVO_EN_MOUVEMENT_VERS_ANGLE_MAX&lt;/code&gt;.&lt;/li&gt;&lt;li&gt; Si le servo est dans l'&#233;tat &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;SERVO_A_ANGLE_MAX&lt;/code&gt; ou&lt;br/&gt; &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;SERVO_EN_MOUVEMENT_VERS_ANGLE_MAX&lt;/code&gt;, la vitesse est mise &#224; -1 et et l'&#233;tat du servo est chang&#233; en &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;SERVO_EN_MOUVEMENT_VERS_ANGLE_MIN&lt;/code&gt;&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;Le programme complet est le suivant.&lt;/p&gt;
&lt;div class=&#034;precode&#034;&gt;&lt;pre data-raccourci=&#034;code&#034; data-language=&#034;C&#034; class='spip_code spip_code_block language-C' dir='ltr' style='text-align:left;'&gt;&lt;code&gt;#include &lt;Servo.h&gt; const byte SERVO_A_ANGLE_MIN = 0; const byte SERVO_A_ANGLE_MAX = 1; const byte SERVO_EN_MOUVEMENT_VERS_ANGLE_MAX = 2; const byte SERVO_EN_MOUVEMENT_VERS_ANGLE_MIN = 3; const int angleMin = 1250; const int angleMax = 1750; Servo monServo; int vitesse = 0; int angle = angleMin; byte etatServo = SERVO_A_ANGLE_MIN; const int pinBouton = 0; /* le bouton est connect&#233; &#224; la broche A0 */ const boolean PRESSE = true; const boolean RELACHE = false; boolean etatBouton = RELACHE; const byte AUCUN_EVENEMENT = 0; const byte EVENEMENT_PRESSE = 1; const byte EVENEMENT_RELACHE = 2; /* * fonctions de gestion du poussoir */ boolean lirePoussoir() { boolean resultat = RELACHE; if (analogRead(pinBouton) &gt; 512) { resultat = PRESSE; } return resultat; } byte lireEvenement() { byte evenement; boolean nouvelEtat = lirePoussoir(); if (nouvelEtat == etatBouton) evenement = AUCUN_EVENEMENT; if (nouvelEtat == PRESSE &amp;&amp; etatBouton == RELACHE) evenement = EVENEMENT_PRESSE; if (nouvelEtat == RELACHE &amp;&amp; etatBouton == PRESSE) evenement = EVENEMENT_RELACHE; etatBouton = nouvelEtat; return evenement; } /* * La fonction setup() est ex&#233;cut&#233;e 1 fois * au d&#233;marrage du programme */ void setup() { monServo.attach(2); } /* * La fonction loop() est ex&#233;cut&#233;e * r&#233;p&#233;titivement */ void loop() { /* actualisation de l'angle du servo */ monServo.writeMicroseconds(angle); angle = angle + vitesse; if (angle &gt; angleMax) { angle = angleMax; vitesse = 0; etatServo = SERVO_A_ANGLE_MAX; } else if (angle &lt; angleMin) { angle = angleMin; vitesse = 0; etatServo = SERVO_A_ANGLE_MIN; } /* lecture de la commande de l'utilisateur */ byte evenement = lireEvenement(); if (evenement == EVENEMENT_PRESSE) { switch (etatServo) { case SERVO_A_ANGLE_MIN: case SERVO_EN_MOUVEMENT_VERS_ANGLE_MIN: vitesse = 1; etatServo = SERVO_EN_MOUVEMENT_VERS_ANGLE_MAX; break; case SERVO_A_ANGLE_MAX: case SERVO_EN_MOUVEMENT_VERS_ANGLE_MAX: vitesse = -1; etatServo = SERVO_EN_MOUVEMENT_VERS_ANGLE_MIN; break; } } delay(3); }&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Ce programme est l'occasion d'introduire une nouvelle construction du C, le &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;switch ... case&lt;/code&gt;. Il s'agit d'un choix multiple. On a vu avec le &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;if ... else ...&lt;/code&gt; un choix double. Ici la valeur de la variable &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;etatServo&lt;/code&gt; indique &#224; quel &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;case&lt;/code&gt; le programme continue son ex&#233;cution. L'ex&#233;cution se poursuit jusqu'&#224; rencontrer un &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;break&lt;/code&gt; qui fait que le programme continue sont ex&#233;cution apr&#232;s le &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;switch&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Distinguer les &#233;tats &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;SERVO_A_ANGLE_MIN&lt;/code&gt; et &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;SERVO_EN_MOUVEMENT_VERS_ANGLE_MIN&lt;/code&gt; n'est pas n&#233;cessaire, idem pour &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;SERVO_A_ANGLE_MAX&lt;/code&gt; et &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;SERVO_EN_MOUVEMENT_VERS_ANGLE_MAX&lt;/code&gt;. On le conserve tout de m&#234;me car le programme est plus lisible ainsi et la distinction qui est faite va nous servir plus tard.&lt;/p&gt;
&lt;p&gt;Une petite vid&#233;o du montage volant et de l'ex&#233;cution de ce dernier programme.&lt;/p&gt;
&lt;div class=&#034;spip_document_249 spip_document spip_documents spip_document_video spip_document_avec_legende&#034; data-legende-len=&#034;28&#034; data-legende-lenx=&#034;&#034;
&gt;
&lt;figure class=&#034;spip_doc_inner&#034;&gt;
&lt;div class=&#034;video-intrinsic-wrapper&#034; style='height:0;width:640px;max-width:100%;padding-bottom:56.25%;position:relative;'&gt; &lt;div class=&#034;video-wrapper&#034; style=&#034;position: absolute;top:0;left:0;width:100%;height:100%;&#034;&gt; &lt;video class=&#034;mejs mejs-249&#034; data-id=&#034;55c926c5efee272582eef1bab2bd2f64&#034; data-mejsoptions='{&#034;iconSprite&#034;: &#034;plugins-dist/medias/lib/mejs/mejs-controls.svg&#034;,&#034;alwaysShowControls&#034;: true,&#034;pluginPath&#034;:&#034;plugins-dist/medias/lib/mejs/&#034;,&#034;loop&#034;:false,&#034;videoWidth&#034;:&#034;100%&#034;,&#034;videoHeight&#034;:&#034;100%&#034;}' width=&#034;100%&#034; height=&#034;100%&#034; controls=&#034;controls&#034; preload=&#034;none&#034; &gt; &lt;source type=&#034;application/x-shockwave-flash&#034; src=&#034;http://www.youtube.com/v/Pvx3_xM7B8E?hl=fr_FR&amp;version=3&amp;rel=0&#034; /&gt; &lt;img src='https://modelleisenbahn.triskell.org/local/cache-vignettes/L64xH64/swf-d2c4d-75a7b.svg?1772798901' width='64' height='64' alt='Impossible de lire la video' /&gt; &lt;/video&gt; &lt;/div&gt;
&lt;/div&gt;
&lt;figcaption class='spip_doc_legende'&gt; &lt;div class='spip_doc_titre crayon document-titre-249 '&gt;&lt;strong&gt;D&#233;monstration du programme
&lt;/strong&gt;&lt;/div&gt; &lt;/figcaption&gt;
&lt;div class=&#034;base64javascript20209960069f2c6729ef848.51775611&#034; title=&#034;PHNjcmlwdD4gdmFyIG1lanNwYXRoPSdwbHVnaW5zLWRpc3QvbWVkaWFzL2xpYi9tZWpzL21lZGlhZWxlbWVudC1hbmQtcGxheWVyLm1pbi5qcz8xNzcyNzk1ODQwJyxtZWpzY3NzPSdwbHVnaW5zLWRpc3QvbWVkaWFzL2xpYi9tZWpzL21lZGlhZWxlbWVudHBsYXllci5taW4uY3NzPzE3NzI3OTU4NDAnOwp2YXIgbWVqc2xvYWRlcjsKKGZ1bmN0aW9uKCl7dmFyIGE9bWVqc2xvYWRlcjsidW5kZWZpbmVkIj09dHlwZW9mIGEmJihtZWpzbG9hZGVyPWE9e2dzOm51bGwscGx1Zzp7fSxjc3M6e30saW5pdDpudWxsLGM6MCxjc3Nsb2FkOm51bGx9KTthLmluaXR8fChhLmNzc2xvYWQ9ZnVuY3Rpb24oYyl7aWYoInVuZGVmaW5lZCI9PXR5cGVvZiBhLmNzc1tjXSl7YS5jc3NbY109ITA7dmFyIGI9ZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgibGluayIpO2IuaHJlZj1jO2IucmVsPSJzdHlsZXNoZWV0IjtiLnR5cGU9InRleHQvY3NzIjtkb2N1bWVudC5nZXRFbGVtZW50c0J5VGFnTmFtZSgiaGVhZCIpWzBdLmFwcGVuZENoaWxkKGIpfX0sYS5pbml0PWZ1bmN0aW9uKCl7ITA9PT1hLmdzJiZmdW5jdGlvbihjKXtqUXVlcnkoImF1ZGlvLm1lanMsdmlkZW8ubWVqcyIpLm5vdCgiLmRvbmUsLm1lanNfX3BsYXllciIpLmVhY2goZnVuY3Rpb24oKXtmdW5jdGlvbiBiKCl7dmFyIGU9ITAsaDtmb3IoaCBpbiBkLmNzcylhLmNzc2xvYWQoZC5jc3NbaF0pO2Zvcih2YXIgZiBpbiBkLnBsdWdpbnMpInVuZGVmaW5lZCI9PQp0eXBlb2YgYS5wbHVnW2ZdPyhlPSExLGEucGx1Z1tmXT0hMSxqUXVlcnkuZ2V0U2NyaXB0KGQucGx1Z2luc1tmXSxmdW5jdGlvbigpe2EucGx1Z1tmXT0hMDtiKCl9KSk6MD09YS5wbHVnW2ZdJiYoZT0hMSk7ZSYmalF1ZXJ5KCIjIitjKS5tZWRpYWVsZW1lbnRwbGF5ZXIoalF1ZXJ5LmV4dGVuZChkLm9wdGlvbnMse3N1Y2Nlc3M6ZnVuY3Rpb24oYSxjKXtmdW5jdGlvbiBiKCl7dmFyIGI9alF1ZXJ5KGEpLmNsb3Nlc3QoIi5tZWpzX19pbm5lciIpO2EucGF1c2VkPyhiLmFkZENsYXNzKCJwYXVzaW5nIiksc2V0VGltZW91dChmdW5jdGlvbigpe2IuZmlsdGVyKCIucGF1c2luZyIpLnJlbW92ZUNsYXNzKCJwbGF5aW5nIikucmVtb3ZlQ2xhc3MoInBhdXNpbmciKS5hZGRDbGFzcygicGF1c2VkIil9LDEwMCkpOmIucmVtb3ZlQ2xhc3MoInBhdXNlZCIpLnJlbW92ZUNsYXNzKCJwYXVzaW5nIikuYWRkQ2xhc3MoInBsYXlpbmciKX1iKCk7YS5hZGRFdmVudExpc3RlbmVyKCJwbGF5IixiLCExKTsKYS5hZGRFdmVudExpc3RlbmVyKCJwbGF5aW5nIixiLCExKTthLmFkZEV2ZW50TGlzdGVuZXIoInBhdXNlIixiLCExKTthLmFkZEV2ZW50TGlzdGVuZXIoInBhdXNlZCIsYiwhMSk7Zy5hdHRyKCJhdXRvcGxheSIpJiZhLnBsYXkoKX19KSl9dmFyIGc9alF1ZXJ5KHRoaXMpLmFkZENsYXNzKCJkb25lIiksYzsoYz1nLmF0dHIoImlkIikpfHwoYz0ibWVqcy0iK2cuYXR0cigiZGF0YS1pZCIpKyItIithLmMrKyxnLmF0dHIoImlkIixjKSk7dmFyIGQ9e29wdGlvbnM6e30scGx1Z2luczp7fSxjc3M6W119LGUsaDtmb3IoZSBpbiBkKWlmKGg9Zy5hdHRyKCJkYXRhLW1lanMiK2UpKWRbZV09alF1ZXJ5LnBhcnNlSlNPTihoKTtiKCl9KX0oalF1ZXJ5KX0pO2EuZ3N8fCgidW5kZWZpbmVkIiE9PXR5cGVvZiBtZWpzY3NzJiZhLmNzc2xvYWQobWVqc2NzcyksYS5ncz1qUXVlcnkuZ2V0U2NyaXB0KG1lanNwYXRoLGZ1bmN0aW9uKCl7YS5ncz0hMDthLmluaXQoKTtqUXVlcnkoYS5pbml0KTtvbkFqYXhMb2FkKGEuaW5pdCl9KSl9KSgpOzwvc2NyaXB0Pg==&#034;&gt;&lt;/div&gt; &lt;/figure&gt;
&lt;/div&gt;&lt;/div&gt;
		
		</content:encoded>


		

	</item>
<item xml:lang="fr">
		<title>Mise en &#339;uvre d'un servo-moteur</title>
		<link>https://modelleisenbahn.triskell.org/spip.php?article57</link>
		<guid isPermaLink="true">https://modelleisenbahn.triskell.org/spip.php?article57</guid>
		<dc:date>2013-11-10T16:29:55Z</dc:date>
		<dc:format>text/html</dc:format>
		<dc:language>fr</dc:language>
		<dc:creator>Jean-Luc</dc:creator>


		<dc:subject>aiguille</dc:subject>
		<dc:subject>servo</dc:subject>
		<dc:subject>Arduino</dc:subject>

		<description>
&lt;p&gt;L'Arduino c'est &#224; la fois une carte &#233;quip&#233;e d'un microcontr&#244;leur et un environnement logiciel qui fournit &#224; l'utilisateur des fonctions pour manipuler le mat&#233;riel de mani&#232;re plus simple que s'il devait mettre en &#339;uvre le micro-contr&#244;leur &#224; partir de rien. &lt;br class='autobr' /&gt;
L'Arduino se programme en langage C et quelques fois en C++. Le C est un langage de programmation tr&#232;s populaire, notamment sur les syst&#232;mes embarqu&#233;s, c'est &#224; dire les syst&#232;mes informatiques int&#233;gr&#233;s dans un proc&#233;d&#233; dans le but de le (&#8230;)&lt;/p&gt;


-
&lt;a href="https://modelleisenbahn.triskell.org/spip.php?rubrique22" rel="directory"&gt;Man&#339;uvre des aiguilles avec des servo-moteurs&lt;/a&gt;

/ 
&lt;a href="https://modelleisenbahn.triskell.org/spip.php?mot4" rel="tag"&gt;aiguille&lt;/a&gt;, 
&lt;a href="https://modelleisenbahn.triskell.org/spip.php?mot5" rel="tag"&gt;servo&lt;/a&gt;, 
&lt;a href="https://modelleisenbahn.triskell.org/spip.php?mot10" rel="tag"&gt;Arduino&lt;/a&gt;

		</description>


 <content:encoded>&lt;div class='rss_texte'&gt;&lt;p&gt;L'Arduino c'est &#224; la fois une carte &#233;quip&#233;e d'un microcontr&#244;leur et un environnement logiciel qui fournit &#224; l'utilisateur des fonctions pour manipuler le mat&#233;riel de mani&#232;re plus simple que s'il devait mettre en &#339;uvre le micro-contr&#244;leur &#224; partir de rien.&lt;/p&gt;
&lt;p&gt;L'Arduino se programme en langage C et quelques fois en C++. Le C est un langage de programmation tr&#232;s populaire, notamment sur les syst&#232;mes embarqu&#233;s, c'est &#224; dire les syst&#232;mes informatiques int&#233;gr&#233;s dans un proc&#233;d&#233; dans le but de le piloter.&lt;/p&gt;
&lt;h2 class=&#034;spip&#034;&gt;Un programme minimum pour Arduino&lt;/h2&gt;
&lt;p&gt;Le programme minimum pour l'Arduino est constitu&#233; de deux fonctions. Une fonction regroupe une s&#233;rie d'instructions et remplit un r&#244;le. Voici ces deux fonctions, &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;setup()&lt;/code&gt; et &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;loop()&lt;/code&gt;. La fonction &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;setup()&lt;/code&gt; est ex&#233;cut&#233;e 1 seule fois au d&#233;but de programme. La fonction &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;loop()&lt;/code&gt; est ex&#233;cut&#233;e r&#233;p&#233;titivement.&lt;/p&gt;
&lt;div class=&#034;precode&#034;&gt;&lt;pre data-raccourci=&#034;code&#034; data-language=&#034;C&#034; class='spip_code spip_code_block language-C' dir='ltr' style='text-align:left;'&gt;&lt;code&gt;/* * La fonction setup() est ex&#233;cut&#233;e 1 fois * au d&#233;marrage du programme */ void setup() { } /* * La fonction loop() est ex&#233;cut&#233;e * r&#233;p&#233;titivement */ void loop() { }&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;en langage C, une fonction retourne une valeur dont le type est indiqu&#233; juste &#224; gauche du nom de la fonction. Il existe plusieurs types de donn&#233;es en C, les nombres entiers positifs et n&#233;gatif (&lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;int&lt;/code&gt;), ceux qui sont seulement positif (&lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;unsigned int&lt;/code&gt;) etc. Nous verrons les types au fur et &#224; mesure des besoins. Ici le type est &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;void&lt;/code&gt;, il s'agit d'un type sp&#233;cial qui signifie &#171; rien &#187; ou &#171; vide &#187; et qui indique que les fonctions &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;setup()&lt;/code&gt; et &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;loop()&lt;/code&gt; ne retournent aucune valeur.&lt;/p&gt;
&lt;p&gt;Une fonction peut prendre des arguments. Les arguments sont donn&#233;s entre les parenth&#232;ses juste apr&#232;s le nom de la fonction. Ici les deux fonctions n'ont aucun argument.&lt;/p&gt;
&lt;p&gt;Les instructions qui constituent la fonction sont donn&#233;es entre les accolades. Ici les deux fonctions sont vides et par cons&#233;quent elle ne font strictement rien.&lt;/p&gt;
&lt;p&gt;Au dessus des fonctions il y a du texte. Il s'agit de commentaires. Un commentaire commence par &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;/*&lt;/code&gt; et termine par &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;*/&lt;/code&gt;. C'est une bonne habitude de commenter abondamment ses programmes. En effet, quelques semaines plus tard, il est difficile de se rappeler de ce que l'on a voulu faire dans un programme et les commentaires explicatifs sont bienvenus.&lt;/p&gt;
&lt;h2 class=&#034;spip&#034;&gt;Mise en &#339;uvre d'un servo-moteur&lt;/h2&gt;
&lt;p&gt;La mise en &#339;uvre d'un servo-moteur avec l'Arduino est ais&#233;e. Il y a une biblioth&#232;que pour &#231;a !&lt;/p&gt;
&lt;p&gt;Une biblioth&#232;que est un jeu de fonctions optionnelles que l'on peut ou non employer dans le programme. Pour utiliser la biblioth&#232;que permettant de piloter des servo-moteurs, il suffit d'inclure, au d&#233;but du programme la directive suivante&lt;/p&gt;
&lt;p&gt;&lt;code data-raccourci=&#034;code&#034; data-language=&#034;C&#034; class='spip_code spip_code_inline language-C' dir='ltr'&gt;#include &lt;Servo.h&gt;&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Il faut ensuite pouvoir manipuler le servo-moteur. Il faut pour cela cr&#233;er une variable de type &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;Servo&lt;/code&gt;. On dit aussi &lt;i&gt;instancier&lt;/i&gt; une variable. Le type &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;Servo&lt;/code&gt; est un peu sp&#233;cial, on entre l&#224; sur le terrain du C++. &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;Servo&lt;/code&gt; est une &lt;i&gt;classe&lt;/i&gt; et cr&#233;er une variable de ce type donne un &lt;i&gt;objet&lt;/i&gt;. En plus de contenir une valeur comme une variable de type nombre entier, un objet poss&#232;de des fonctions qui agissent sur lui. Dans le monde de l'objet on appelle commun&#233;ment ces fonctions des &lt;i&gt;m&#233;thodes&lt;/i&gt;. Nous n'avons pas besoin d'en conna&#238;tre plus pour utiliser un objet de type &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;Servo&lt;/code&gt;. Voici comment on cr&#233;e une variable, que nous appelons &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;monServo&lt;/code&gt; de type &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;Servo&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;code data-raccourci=&#034;code&#034; data-language=&#034;C&#034; class='spip_code spip_code_inline language-C' dir='ltr'&gt;Servo monServo;&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Notez le &#171; ; &#187; qui termine la ligne, il est n&#233;cessaire et termine la directive. Notez aussi que le respect des majuscules et des minuscules est important car le langage C fait la diff&#233;rence entre &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;s&lt;/code&gt; et &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;S&lt;/code&gt; par exemple. Par cons&#233;quent appeler la variable &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;monServo&lt;/code&gt; n'est pas la m&#234;me chose que de l'appeler &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;monservo&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;La variable &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;monServo&lt;/code&gt; est instanci&#233;e, il faut maintenant l'accrocher &#224; une des sorties num&#233;riques de l'Arduino. Nous allons choisir la sortie 2 car les sorties 0 et 1 ont un r&#244;le particulier : elles permettent d'envoyer des messages qui seront affich&#233;s sur votre ordinateur h&#244;te. Il s'agit d'une aide irrempla&#231;able qui se r&#233;v&#232;le n&#233;cessaire pour comprendre ce qui se passe quand le programme ne fait pas ce que l'on attend.&lt;br class='autobr' /&gt;
Accrocher la variable &#224; une sortie se fait avec la m&#233;thode &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;attach&lt;/code&gt; et, &#233;videmment, dans la fonction &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;setup()&lt;/code&gt; car il est inutile de le faire plus d'une fois.&lt;/p&gt;
&lt;div class=&#034;precode&#034;&gt;&lt;pre data-raccourci=&#034;code&#034; data-language=&#034;C&#034; class='spip_code spip_code_block language-C' dir='ltr' style='text-align:left;'&gt;&lt;code&gt;void setup() { monServo.attach(2); /* accroche monServo &#224; la pin 2 de l'Arduino */ }&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;Aller-retours&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;La premi&#232;re application est tr&#232;s simple, il s'agit de faire faire au servo des aller-retours de part et d'autre de la position m&#233;diane. La m&#233;thode &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;write(...)&lt;/code&gt; permet de donner l'angle auquel le servo doit se positionner. L'argument est une valeur comprise entre 0 et 180&#176;. L'angle minimum choisi est donc de 70&#176; et l'angle maximum de 110&#176;. On fixe la pause entre 2 changements de position &#224; 1s. La fonction &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;loop()&lt;/code&gt; est donc la suivante.&lt;/p&gt;
&lt;div class=&#034;precode&#034;&gt;&lt;pre data-raccourci=&#034;code&#034; data-language=&#034;C&#034; class='spip_code spip_code_block language-C' dir='ltr' style='text-align:left;'&gt;&lt;code&gt;void loop() { /* positionne le servo &#224; 70&#176; */ monServo.write(70); /* attend 1000 ms */ delay(1000); /* positionne le servo &#224; 110&#176; */ monServo.write(110); /* attend 1000 ms */ delay(1000); }&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Cette premi&#232;re application ne remplit pas le cahier des charges. &#192; savoir un mouvement lent. Le mouvement a bien lieu toutes les secondes mais il est tr&#232;s rapide, quasi instantan&#233;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Aller-retours lents&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Pour obtenir un mouvement lent, il faut faire varier l'angle du servo progressivement. Pour cela, il faut changer l'angle tr&#232;s tr&#232;s peu et le faire plus souvent. Fixons par exemple un changement d'angle de 1&#176;. Si l'on veut que le mouvement, passer de 70&#176; &#224; 110&#176; soit accompli en 1s, il faut augmenter l'angle de 1&#176; toutes les 1000ms / (110 - 70). soit une pause de 25ms. Quand l'angle atteint 110&#176;, il faut inverser le mouvement. Quand l'angle atteint 70&#176;, il faut de nouveau inverser le mouvement. Nous avons donc besoin de deux variables, &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;angle&lt;/code&gt; qui contient l'angle courant du servo et &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;vitesse&lt;/code&gt; qui contient 1 si on augmente l'angle et -1 si on le diminue. Pour faciliter la programmation, on va placer 70 et 110 dans deux constantes. Le programme est le suivant.&lt;/p&gt;
&lt;p&gt;&lt;i&gt;Programme 2&lt;/i&gt;&lt;/p&gt;
&lt;div class=&#034;precode&#034;&gt;&lt;pre data-raccourci=&#034;code&#034; data-language=&#034;C&#034; class='spip_code spip_code_block language-C' dir='ltr' style='text-align:left;'&gt;&lt;code&gt;#include &lt;Servo.h&gt; Servo monServo; int vitesse; int angle; const int angleMin = 70; const int angleMax = 110; /* * La fonction setup() est ex&#233;cut&#233;e 1 fois * au d&#233;marrage du programme */ void setup() { monServo.attach(2); angle = angleMin; vitesse = 1; } /* * La fonction loop() est ex&#233;cut&#233;e * r&#233;p&#233;titivement */ void loop() { monServo.write(angle); /* calcule le nouvel angle */ angle = angle + vitesse; if (angle &gt; angleMax) { /* * le nouvel angle d&#233;passe le maximum * on le recale au maximum et on inverse la vitesse */ angle = angleMax; vitesse = -1; } else if (angle &lt; angleMin) { /* * le nouvel angle d&#233;passe le minimum * on le recale au minimum et on inverse la vitesse */ angle = angleMin; vitesse = 1; } delay(25); }&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Le mouvement est bien lent comme on le d&#233;sire mais avec une variation de l'angle par degr&#233;, le mouvement est un peu saccad&#233;. Une autre m&#233;thode permet un positionnement plus pr&#233;cis. Il s'agit de la m&#233;thode &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;writeMicroseconds(...)&lt;/code&gt;. L'argument de cette m&#233;thode n'est plus un angle mais la dur&#233;e de l'impulsion de commande du servo-moteur en micro-secondes. En effet, le signal de commande du servo-moteur est une impulsion dont la largeur d&#233;termine la position du servo (plus d'informations sont donn&#233;es dans l'article &#171; &lt;a href='https://modelleisenbahn.triskell.org/spip.php?article36' class=&#034;spip_in&#034;&gt;La carte de commande 6 servo-moteurs, le mat&#233;riel&lt;/a&gt; &#187;, une autre mise en &#339;uvre utilisant une conception mat&#233;rielle personnelle). Cette impulsion a donc la forme suivante.&lt;/p&gt;
&lt;div class='spip_document_101 spip_document spip_documents spip_document_image spip_documents_center spip_document_center spip_document_avec_legende' data-legende-len=&#034;169&#034; data-legende-lenx=&#034;xxx&#034;
&gt;
&lt;figure class=&#034;spip_doc_inner&#034;&gt; &lt;img src='https://modelleisenbahn.triskell.org/local/cache-vignettes/L413xH268/commande_servo-68ed1.png?1692301737' width='413' height='268' alt='' /&gt;
&lt;figcaption class='spip_doc_legende'&gt; &lt;div class='spip_doc_titre crayon document-titre-101 '&gt;&lt;strong&gt;La PWM de commande d'un servo
&lt;/strong&gt;&lt;/div&gt; &lt;div class='spip_doc_descriptif crayon document-descriptif-101 '&gt;Seuls les dur&#233;es extr&#234;mes de l'impulsion et la dur&#233;e m&#233;diane sont montr&#233;es mais toutes les valeurs entre 0,5 ms et 2,5 ms sont possibles.
&lt;/div&gt; &lt;/figcaption&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;p&gt;La valeur m&#233;diane est donc de 1500&#181;s et les valeurs minimum et maximum pour les angles que nous avions fix&#233;s deviennent respectivement et approximativement 1250 et 1750. On va conserver une vitesse de 1 ou -1 et pour avoir un mouvement d'1s alors que l'on franchi 500 pas d'angle on va d&#233;sormais faire une pause de 2ms. Le programme est donc le suivant.&lt;/p&gt;
&lt;p&gt;&lt;i&gt;Programme 3&lt;/i&gt;&lt;/p&gt;
&lt;div class=&#034;precode&#034;&gt;&lt;pre data-raccourci=&#034;code&#034; data-language=&#034;C&#034; class='spip_code spip_code_block language-C' dir='ltr' style='text-align:left;'&gt;&lt;code&gt;#include &lt;Servo.h&gt; Servo monServo; int vitesse; int angle; const int angleMin = 1250; const int angleMax = 1750; /* * La fonction setup() est ex&#233;cut&#233;e 1 fois * au d&#233;marrage du programme */ void setup() { monServo.attach(2); angle = angleMin; vitesse = 1; } /* * La fonction loop() est ex&#233;cut&#233;e * r&#233;p&#233;titivement */ void loop() { monServo.writeMicroseconds(angle); /* calcule le nouvel angle */ angle = angle + vitesse; if (angle &gt; angleMax) { /* * le nouvel angle d&#233;passe le maximum * on le recale au maximum et on inverse la vitesse */ angle = angleMax; vitesse = -1; } else if (angle &lt; angleMin) { /* * le nouvel angle d&#233;passe le minimum * on le recale au minimum et on inverse la vitesse */ angle = angleMin; vitesse = 1; } delay(2); }&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Le r&#233;sultat est meilleur avec un mouvement plus fluide.&lt;/p&gt;
&lt;p&gt;Voici qui conclut cette prise en main des servo-moteurs. Le prochain article portera sur l'ajout d'un bouton permettant de commander le mouvement du servo-moteur.&lt;/p&gt;
&lt;div class=&#034;spip_document_247 spip_document spip_documents spip_document_video spip_document_avec_legende&#034; data-legende-len=&#034;42&#034; data-legende-lenx=&#034;x&#034;
&gt;
&lt;figure class=&#034;spip_doc_inner&#034;&gt;
&lt;div class=&#034;video-intrinsic-wrapper&#034; style='height:0;width:640px;max-width:100%;padding-bottom:56.25%;position:relative;'&gt; &lt;div class=&#034;video-wrapper&#034; style=&#034;position: absolute;top:0;left:0;width:100%;height:100%;&#034;&gt; &lt;video class=&#034;mejs mejs-247&#034; data-id=&#034;0f1a830c9eb90a40d479b23163597010&#034; data-mejsoptions='{&#034;iconSprite&#034;: &#034;plugins-dist/medias/lib/mejs/mejs-controls.svg&#034;,&#034;alwaysShowControls&#034;: true,&#034;pluginPath&#034;:&#034;plugins-dist/medias/lib/mejs/&#034;,&#034;loop&#034;:false,&#034;videoWidth&#034;:&#034;100%&#034;,&#034;videoHeight&#034;:&#034;100%&#034;}' width=&#034;100%&#034; height=&#034;100%&#034; controls=&#034;controls&#034; preload=&#034;none&#034; &gt; &lt;source type=&#034;application/x-shockwave-flash&#034; src=&#034;http://www.youtube.com/v/mwEpmugy3G8?hl=fr_FR&amp;version=3&amp;rel=0&#034; /&gt; &lt;img src='https://modelleisenbahn.triskell.org/local/cache-vignettes/L64xH64/swf-d2c4d-75a7b.svg?1772798901' width='64' height='64' alt='Impossible de lire la video' /&gt; &lt;/video&gt; &lt;/div&gt;
&lt;/div&gt;
&lt;figcaption class='spip_doc_legende'&gt; &lt;div class='spip_doc_titre crayon document-titre-247 '&gt;&lt;strong&gt;Mise en &#339;uvre des 3 programmes pr&#233;sent&#233;s
&lt;/strong&gt;&lt;/div&gt; &lt;/figcaption&gt;
&lt;div class=&#034;base64javascript20209960069f2c6729ef848.51775611&#034; title=&#034;PHNjcmlwdD4gdmFyIG1lanNwYXRoPSdwbHVnaW5zLWRpc3QvbWVkaWFzL2xpYi9tZWpzL21lZGlhZWxlbWVudC1hbmQtcGxheWVyLm1pbi5qcz8xNzcyNzk1ODQwJyxtZWpzY3NzPSdwbHVnaW5zLWRpc3QvbWVkaWFzL2xpYi9tZWpzL21lZGlhZWxlbWVudHBsYXllci5taW4uY3NzPzE3NzI3OTU4NDAnOwp2YXIgbWVqc2xvYWRlcjsKKGZ1bmN0aW9uKCl7dmFyIGE9bWVqc2xvYWRlcjsidW5kZWZpbmVkIj09dHlwZW9mIGEmJihtZWpzbG9hZGVyPWE9e2dzOm51bGwscGx1Zzp7fSxjc3M6e30saW5pdDpudWxsLGM6MCxjc3Nsb2FkOm51bGx9KTthLmluaXR8fChhLmNzc2xvYWQ9ZnVuY3Rpb24oYyl7aWYoInVuZGVmaW5lZCI9PXR5cGVvZiBhLmNzc1tjXSl7YS5jc3NbY109ITA7dmFyIGI9ZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgibGluayIpO2IuaHJlZj1jO2IucmVsPSJzdHlsZXNoZWV0IjtiLnR5cGU9InRleHQvY3NzIjtkb2N1bWVudC5nZXRFbGVtZW50c0J5VGFnTmFtZSgiaGVhZCIpWzBdLmFwcGVuZENoaWxkKGIpfX0sYS5pbml0PWZ1bmN0aW9uKCl7ITA9PT1hLmdzJiZmdW5jdGlvbihjKXtqUXVlcnkoImF1ZGlvLm1lanMsdmlkZW8ubWVqcyIpLm5vdCgiLmRvbmUsLm1lanNfX3BsYXllciIpLmVhY2goZnVuY3Rpb24oKXtmdW5jdGlvbiBiKCl7dmFyIGU9ITAsaDtmb3IoaCBpbiBkLmNzcylhLmNzc2xvYWQoZC5jc3NbaF0pO2Zvcih2YXIgZiBpbiBkLnBsdWdpbnMpInVuZGVmaW5lZCI9PQp0eXBlb2YgYS5wbHVnW2ZdPyhlPSExLGEucGx1Z1tmXT0hMSxqUXVlcnkuZ2V0U2NyaXB0KGQucGx1Z2luc1tmXSxmdW5jdGlvbigpe2EucGx1Z1tmXT0hMDtiKCl9KSk6MD09YS5wbHVnW2ZdJiYoZT0hMSk7ZSYmalF1ZXJ5KCIjIitjKS5tZWRpYWVsZW1lbnRwbGF5ZXIoalF1ZXJ5LmV4dGVuZChkLm9wdGlvbnMse3N1Y2Nlc3M6ZnVuY3Rpb24oYSxjKXtmdW5jdGlvbiBiKCl7dmFyIGI9alF1ZXJ5KGEpLmNsb3Nlc3QoIi5tZWpzX19pbm5lciIpO2EucGF1c2VkPyhiLmFkZENsYXNzKCJwYXVzaW5nIiksc2V0VGltZW91dChmdW5jdGlvbigpe2IuZmlsdGVyKCIucGF1c2luZyIpLnJlbW92ZUNsYXNzKCJwbGF5aW5nIikucmVtb3ZlQ2xhc3MoInBhdXNpbmciKS5hZGRDbGFzcygicGF1c2VkIil9LDEwMCkpOmIucmVtb3ZlQ2xhc3MoInBhdXNlZCIpLnJlbW92ZUNsYXNzKCJwYXVzaW5nIikuYWRkQ2xhc3MoInBsYXlpbmciKX1iKCk7YS5hZGRFdmVudExpc3RlbmVyKCJwbGF5IixiLCExKTsKYS5hZGRFdmVudExpc3RlbmVyKCJwbGF5aW5nIixiLCExKTthLmFkZEV2ZW50TGlzdGVuZXIoInBhdXNlIixiLCExKTthLmFkZEV2ZW50TGlzdGVuZXIoInBhdXNlZCIsYiwhMSk7Zy5hdHRyKCJhdXRvcGxheSIpJiZhLnBsYXkoKX19KSl9dmFyIGc9alF1ZXJ5KHRoaXMpLmFkZENsYXNzKCJkb25lIiksYzsoYz1nLmF0dHIoImlkIikpfHwoYz0ibWVqcy0iK2cuYXR0cigiZGF0YS1pZCIpKyItIithLmMrKyxnLmF0dHIoImlkIixjKSk7dmFyIGQ9e29wdGlvbnM6e30scGx1Z2luczp7fSxjc3M6W119LGUsaDtmb3IoZSBpbiBkKWlmKGg9Zy5hdHRyKCJkYXRhLW1lanMiK2UpKWRbZV09alF1ZXJ5LnBhcnNlSlNPTihoKTtiKCl9KX0oalF1ZXJ5KX0pO2EuZ3N8fCgidW5kZWZpbmVkIiE9PXR5cGVvZiBtZWpzY3NzJiZhLmNzc2xvYWQobWVqc2NzcyksYS5ncz1qUXVlcnkuZ2V0U2NyaXB0KG1lanNwYXRoLGZ1bmN0aW9uKCl7YS5ncz0hMDthLmluaXQoKTtqUXVlcnkoYS5pbml0KTtvbkFqYXhMb2FkKGEuaW5pdCl9KSl9KSgpOzwvc2NyaXB0Pg==&#034;&gt;&lt;/div&gt; &lt;/figure&gt;
&lt;/div&gt;&lt;/div&gt;
		
		</content:encoded>


		

	</item>
<item xml:lang="fr">
		<title>Description du syst&#232;me</title>
		<link>https://modelleisenbahn.triskell.org/spip.php?article56</link>
		<guid isPermaLink="true">https://modelleisenbahn.triskell.org/spip.php?article56</guid>
		<dc:date>2013-11-10T11:35:53Z</dc:date>
		<dc:format>text/html</dc:format>
		<dc:language>fr</dc:language>
		<dc:creator>Jean-Luc</dc:creator>


		<dc:subject>aiguille</dc:subject>
		<dc:subject>servo</dc:subject>
		<dc:subject>Arduino</dc:subject>

		<description>
&lt;p&gt;Une petite r&#233;cr&#233;ation par rapport &#224; la construction de mon r&#233;seau. Je bricole un peu d'Arduino avec ma fille pour animer des petits robots. Et qui dit robots dit servo-moteurs. Il se trouve que c'est aussi li&#233; au mod&#233;lisme ferroviaire, d'o&#249; la pr&#233;sence de cet article sur mon blog. &lt;br class='autobr' /&gt;
En effet, l'Arduino me semble &#234;tre une excellente solution pour mettre en &#339;uvre des syst&#232;mes &#233;lectroniques et &#233;lectro-m&#233;caniques sophistiqu&#233;s sur un r&#233;seau. La man&#339;uvre des aiguilles via des servo-moteurs en est (&#8230;)&lt;/p&gt;


-
&lt;a href="https://modelleisenbahn.triskell.org/spip.php?rubrique22" rel="directory"&gt;Man&#339;uvre des aiguilles avec des servo-moteurs&lt;/a&gt;

/ 
&lt;a href="https://modelleisenbahn.triskell.org/spip.php?mot4" rel="tag"&gt;aiguille&lt;/a&gt;, 
&lt;a href="https://modelleisenbahn.triskell.org/spip.php?mot5" rel="tag"&gt;servo&lt;/a&gt;, 
&lt;a href="https://modelleisenbahn.triskell.org/spip.php?mot10" rel="tag"&gt;Arduino&lt;/a&gt;

		</description>


 <content:encoded>&lt;div class='rss_texte'&gt;&lt;p&gt;Une petite r&#233;cr&#233;ation par rapport &#224; la construction de mon r&#233;seau. Je bricole un peu d'&lt;a href=&#034;http://arduino.cc&#034; class=&#034;spip_out&#034; rel=&#034;external&#034;&gt;Arduino&lt;/a&gt; avec ma fille pour animer des petits robots. Et qui dit robots dit servo-moteurs. Il se trouve que c'est aussi li&#233; au mod&#233;lisme ferroviaire, d'o&#249; la pr&#233;sence de cet article sur mon blog.&lt;/p&gt;
&lt;p&gt;En effet, l'Arduino me semble &#234;tre une excellente solution pour mettre en &#339;uvre des syst&#232;mes &#233;lectroniques et &#233;lectro-m&#233;caniques sophistiqu&#233;s sur un r&#233;seau. La man&#339;uvre des aiguilles via des servo-moteurs en est un exemple qui reste d'une complexit&#233; raisonnable tout en r&#233;pondant &#224; un besoin exprim&#233; par ceux qui exploitent leur r&#233;seau en analogique.&lt;/p&gt;
&lt;p&gt;&lt;i&gt;&lt;a href=&#034;http://www.tamvalleydepot.com&#034; class=&#034;spip_out&#034; rel=&#034;external&#034;&gt;Tam Valley Depot&lt;/a&gt;&lt;/i&gt; commercialise une carte de ce type, l'&lt;a href=&#034;http://www.tamvalleydepot.com/products/octopusservodriver.html&#034; class=&#034;spip_out&#034; rel=&#034;external&#034;&gt;Octopus III&lt;/a&gt;. Nous allons reproduire le fonctionnement de cette carte en utilisant un &lt;a href=&#034;http://arduino.cc/en/Main/ArduinoBoardUno&#034; class=&#034;spip_out&#034; rel=&#034;external&#034;&gt;Arduino Uno&lt;/a&gt; quelques LED et quelques poussoirs. Je dis nous car ces articles sont con&#231;us comme un tutoriel pour expliquer le fonctionnement du syst&#232;me Arduino et son application en mod&#233;lisme ferroviaire. En parall&#232;le &lt;a href=&#034;http://forum.e-train.fr/viewforum.php?f=63&#034; class=&#034;spip_out&#034; rel=&#034;external&#034;&gt;un forum sp&#233;cifique a &#233;t&#233; mis en place&lt;/a&gt; sur le forum Loco-Revue sous la houlette de Christian B&#233;zanger, auteur de la s&#233;rie d'articles sur l'Arduino dans la revue &#233;ponyme et les id&#233;es bouillonnent.&lt;/p&gt;
&lt;h2 class=&#034;spip&#034;&gt;Que veut-on comme fonction ?&lt;/h2&gt;
&lt;p&gt;Fonctionnellement, l'utilisateur veut le syst&#232;me classique. Il dispose d'une batterie de boutons, un par aiguille. Une pression sur un bouton change la position de l'aiguille. Nous allons pr&#233;voir ici 8 aiguilles et donc 8 servo-moteurs et 8 boutons. Son objectif est bien s&#251;r d'avoir un mouvement lent et r&#233;aliste.&lt;/p&gt;
&lt;p&gt;Il veut aussi un retour sur la position, par exemple une LED verte signifie que l'aiguille est droite et une jaune que l'aiguille est d&#233;vi&#233;e.&lt;/p&gt;
&lt;p&gt;Enfin, chaque moteur d'aiguille pouvant &#234;tre diff&#233;rent, il veut r&#233;gler les deux positions extr&#234;mes servo par servo. Il faut donc qu'il puisse indiquer qu'il veut r&#233;gler les servos puis pr&#233;ciser le servo qu'il souhaite r&#233;gler puis disposer d'un dispositif de r&#233;glage.&lt;/p&gt;
&lt;h2 class=&#034;spip&#034;&gt;De quel mat&#233;riel a-t-on besoin ?&lt;/h2&gt;
&lt;p&gt;Du point de vue physique, le syst&#232;me que nous allons concevoir est constitu&#233; de :&lt;/p&gt;
&lt;ul class=&#034;spip&#034; role=&#034;list&#034;&gt;&lt;li&gt; Un Arduino Uno. Il s'agit d'une petite carte embarquant un micro-contr&#244;leur ATMega328, un r&#233;gulateur de tension 5V pour l'Arduino et ce qu'on peut y brancher et une &#233;lectronique de programmation qui permet d'envoyer un programme sur l'Arduino via la liaison USB de l'ordinateur ;&lt;/li&gt;&lt;li&gt; 8 servos-moteur ;&lt;/li&gt;&lt;li&gt; 8 boutons poussoir, 1 pour chaque servo-moteur, permettant de changer la position du servo-moteur correspondant ;&lt;/li&gt;&lt;li&gt; Un bouton rotatif &#224; 8 positions pour s&#233;lectionner un servo-moteur afin de r&#233;gler ses but&#233;es (mode r&#233;glage). Un commutateur ou un poussoir permettant de passer du mode r&#233;glage au mode exploitation. Le mode exploitation est le fonctionnement normal du dispositif ;&lt;/li&gt;&lt;li&gt; Une paire de poussoirs pour le r&#233;glage des but&#233;es des servo-moteurs ;&lt;/li&gt;&lt;li&gt; Des r&#233;sistances de tirage ;&lt;/li&gt;&lt;li&gt; 16 LED, 8 vertes et 8 jaunes, pour les temoins ;&lt;/li&gt;&lt;/ul&gt;&lt;div class=&#034;spip_document_245 spip_document spip_documents spip_document_video spip_document_avec_legende&#034; data-legende-len=&#034;84&#034; data-legende-lenx=&#034;xx&#034;
&gt;
&lt;figure class=&#034;spip_doc_inner&#034;&gt;
&lt;div class=&#034;video-intrinsic-wrapper&#034; style='height:0;width:640px;max-width:100%;padding-bottom:56.25%;position:relative;'&gt; &lt;div class=&#034;video-wrapper&#034; style=&#034;position: absolute;top:0;left:0;width:100%;height:100%;&#034;&gt; &lt;video class=&#034;mejs mejs-245&#034; data-id=&#034;79a0d68c462b23ca7ccc337ea8224e01&#034; data-mejsoptions='{&#034;iconSprite&#034;: &#034;plugins-dist/medias/lib/mejs/mejs-controls.svg&#034;,&#034;alwaysShowControls&#034;: true,&#034;pluginPath&#034;:&#034;plugins-dist/medias/lib/mejs/&#034;,&#034;loop&#034;:false,&#034;videoWidth&#034;:&#034;100%&#034;,&#034;videoHeight&#034;:&#034;100%&#034;}' width=&#034;100%&#034; height=&#034;100%&#034; controls=&#034;controls&#034; preload=&#034;none&#034; &gt; &lt;source type=&#034;application/x-shockwave-flash&#034; src=&#034;http://www.youtube.com/v/8JfvVj9_f6E?hl=fr_FR&amp;version=3&amp;rel=0&#034; /&gt; &lt;img src='https://modelleisenbahn.triskell.org/local/cache-vignettes/L64xH64/swf-d2c4d-75a7b.svg?1772798901' width='64' height='64' alt='Impossible de lire la video' /&gt; &lt;/video&gt; &lt;/div&gt;
&lt;/div&gt;
&lt;figcaption class='spip_doc_legende'&gt; &lt;div class='spip_doc_titre crayon document-titre-245 '&gt;&lt;strong&gt;Courte pr&#233;sentation de l'Arduino Uno et des servo-moteurs que nous allons utiliser
&lt;/strong&gt;&lt;/div&gt; &lt;/figcaption&gt;
&lt;div class=&#034;base64javascript20209960069f2c6729ef848.51775611&#034; title=&#034;PHNjcmlwdD4gdmFyIG1lanNwYXRoPSdwbHVnaW5zLWRpc3QvbWVkaWFzL2xpYi9tZWpzL21lZGlhZWxlbWVudC1hbmQtcGxheWVyLm1pbi5qcz8xNzcyNzk1ODQwJyxtZWpzY3NzPSdwbHVnaW5zLWRpc3QvbWVkaWFzL2xpYi9tZWpzL21lZGlhZWxlbWVudHBsYXllci5taW4uY3NzPzE3NzI3OTU4NDAnOwp2YXIgbWVqc2xvYWRlcjsKKGZ1bmN0aW9uKCl7dmFyIGE9bWVqc2xvYWRlcjsidW5kZWZpbmVkIj09dHlwZW9mIGEmJihtZWpzbG9hZGVyPWE9e2dzOm51bGwscGx1Zzp7fSxjc3M6e30saW5pdDpudWxsLGM6MCxjc3Nsb2FkOm51bGx9KTthLmluaXR8fChhLmNzc2xvYWQ9ZnVuY3Rpb24oYyl7aWYoInVuZGVmaW5lZCI9PXR5cGVvZiBhLmNzc1tjXSl7YS5jc3NbY109ITA7dmFyIGI9ZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgibGluayIpO2IuaHJlZj1jO2IucmVsPSJzdHlsZXNoZWV0IjtiLnR5cGU9InRleHQvY3NzIjtkb2N1bWVudC5nZXRFbGVtZW50c0J5VGFnTmFtZSgiaGVhZCIpWzBdLmFwcGVuZENoaWxkKGIpfX0sYS5pbml0PWZ1bmN0aW9uKCl7ITA9PT1hLmdzJiZmdW5jdGlvbihjKXtqUXVlcnkoImF1ZGlvLm1lanMsdmlkZW8ubWVqcyIpLm5vdCgiLmRvbmUsLm1lanNfX3BsYXllciIpLmVhY2goZnVuY3Rpb24oKXtmdW5jdGlvbiBiKCl7dmFyIGU9ITAsaDtmb3IoaCBpbiBkLmNzcylhLmNzc2xvYWQoZC5jc3NbaF0pO2Zvcih2YXIgZiBpbiBkLnBsdWdpbnMpInVuZGVmaW5lZCI9PQp0eXBlb2YgYS5wbHVnW2ZdPyhlPSExLGEucGx1Z1tmXT0hMSxqUXVlcnkuZ2V0U2NyaXB0KGQucGx1Z2luc1tmXSxmdW5jdGlvbigpe2EucGx1Z1tmXT0hMDtiKCl9KSk6MD09YS5wbHVnW2ZdJiYoZT0hMSk7ZSYmalF1ZXJ5KCIjIitjKS5tZWRpYWVsZW1lbnRwbGF5ZXIoalF1ZXJ5LmV4dGVuZChkLm9wdGlvbnMse3N1Y2Nlc3M6ZnVuY3Rpb24oYSxjKXtmdW5jdGlvbiBiKCl7dmFyIGI9alF1ZXJ5KGEpLmNsb3Nlc3QoIi5tZWpzX19pbm5lciIpO2EucGF1c2VkPyhiLmFkZENsYXNzKCJwYXVzaW5nIiksc2V0VGltZW91dChmdW5jdGlvbigpe2IuZmlsdGVyKCIucGF1c2luZyIpLnJlbW92ZUNsYXNzKCJwbGF5aW5nIikucmVtb3ZlQ2xhc3MoInBhdXNpbmciKS5hZGRDbGFzcygicGF1c2VkIil9LDEwMCkpOmIucmVtb3ZlQ2xhc3MoInBhdXNlZCIpLnJlbW92ZUNsYXNzKCJwYXVzaW5nIikuYWRkQ2xhc3MoInBsYXlpbmciKX1iKCk7YS5hZGRFdmVudExpc3RlbmVyKCJwbGF5IixiLCExKTsKYS5hZGRFdmVudExpc3RlbmVyKCJwbGF5aW5nIixiLCExKTthLmFkZEV2ZW50TGlzdGVuZXIoInBhdXNlIixiLCExKTthLmFkZEV2ZW50TGlzdGVuZXIoInBhdXNlZCIsYiwhMSk7Zy5hdHRyKCJhdXRvcGxheSIpJiZhLnBsYXkoKX19KSl9dmFyIGc9alF1ZXJ5KHRoaXMpLmFkZENsYXNzKCJkb25lIiksYzsoYz1nLmF0dHIoImlkIikpfHwoYz0ibWVqcy0iK2cuYXR0cigiZGF0YS1pZCIpKyItIithLmMrKyxnLmF0dHIoImlkIixjKSk7dmFyIGQ9e29wdGlvbnM6e30scGx1Z2luczp7fSxjc3M6W119LGUsaDtmb3IoZSBpbiBkKWlmKGg9Zy5hdHRyKCJkYXRhLW1lanMiK2UpKWRbZV09alF1ZXJ5LnBhcnNlSlNPTihoKTtiKCl9KX0oalF1ZXJ5KX0pO2EuZ3N8fCgidW5kZWZpbmVkIiE9PXR5cGVvZiBtZWpzY3NzJiZhLmNzc2xvYWQobWVqc2NzcyksYS5ncz1qUXVlcnkuZ2V0U2NyaXB0KG1lanNwYXRoLGZ1bmN0aW9uKCl7YS5ncz0hMDthLmluaXQoKTtqUXVlcnkoYS5pbml0KTtvbkFqYXhMb2FkKGEuaW5pdCl9KSl9KSgpOzwvc2NyaXB0Pg==&#034;&gt;&lt;/div&gt; &lt;/figure&gt;
&lt;/div&gt;
&lt;p&gt;Certains points peuvent sembler obscurs pour l'instant mais nous allons revenir dessus et les choses s'&#233;clairciront.&lt;/p&gt;
&lt;p&gt;L'&#233;lectronique est r&#233;duite &#224; sa plus simple expression et elle sera expliqu&#233;e au fur et &#224; mesure.&lt;/p&gt;
&lt;p&gt;Enfin la plus grosse partie du travail est &#233;videmment le logiciel. Plut&#244;t que d'aborder cette partie de mani&#232;re acad&#233;mique nous allons la voir au travers de la mise en &#339;uvre de notre application, en amenant les explications sur la programmation au fur et &#224; mesure que le besoin s'en fait sentir. Nous n'allons donc pas faire de conception globale de notre application comme cela se fait dans l'industrie&lt;span class=&#034;spip_note_ref&#034;&gt; [&lt;a href=&#034;#nb3-1&#034; class=&#034;spip_note&#034; rel=&#034;appendix&#034; title=&#034;Bon, en fait j'ai d&#233;j&#224; fait cette conception, rassurez-vous.&#034; id=&#034;nh3-1&#034;&gt;1&lt;/a&gt;]&lt;/span&gt; mais pr&#233;senter des sous-ensembles restreints permettant de saisir les concepts pour ensuite, une brique apr&#232;s l'autre, construire l'application.&lt;/p&gt;&lt;/div&gt;
		&lt;hr /&gt;
		&lt;div class='rss_notes'&gt;&lt;div id=&#034;nb3-1&#034;&gt;
&lt;p&gt;&lt;span class=&#034;spip_note_ref&#034;&gt;[&lt;a href=&#034;#nh3-1&#034; class=&#034;spip_note&#034; title=&#034;Notes 3-1&#034; rev=&#034;appendix&#034;&gt;1&lt;/a&gt;] &lt;/span&gt;Bon, en fait j'ai d&#233;j&#224; fait cette conception, rassurez-vous.&lt;/p&gt;
&lt;/div&gt;&lt;/div&gt;
		
		</content:encoded>


		

	</item>
<item xml:lang="fr">
		<title>Conception et mise en &#339;uvre</title>
		<link>https://modelleisenbahn.triskell.org/spip.php?article35</link>
		<guid isPermaLink="true">https://modelleisenbahn.triskell.org/spip.php?article35</guid>
		<dc:date>2013-07-01T16:56:34Z</dc:date>
		<dc:format>text/html</dc:format>
		<dc:language>fr</dc:language>
		<dc:creator>Jean-Luc</dc:creator>


		<dc:subject>aiguille</dc:subject>
		<dc:subject>servo</dc:subject>

		<description>
&lt;p&gt;Comme pr&#233;sent&#233; dans &#171; &#201;tat de l'art &#187;, il existe de nombreuses fa&#231;ons de monter un servo-moteur en mod&#233;lisme ferroviaire. Voici la solution choisie sur mon r&#233;seau. Il s'agit d'une solution similaire &#224; celle de Pierre mais adapt&#233;e &#224; des micro-servos. &lt;br class='autobr' /&gt;
Cahier des charges &lt;br class='autobr' /&gt;
L'actionneur doit r&#233;pondre &#224; des exigences de mise en &#339;uvre : Un encombrement raisonnable. Notamment, il doit &#234;tre possible de mettre deux actionneurs c&#244;te &#224; c&#244;te sur deux voies parall&#232;les avec un entraxe de 26,5mm (entraxe (&#8230;)&lt;/p&gt;


-
&lt;a href="https://modelleisenbahn.triskell.org/spip.php?rubrique16" rel="directory"&gt;Actionneurs &#224; servo-moteurs&lt;/a&gt;

/ 
&lt;a href="https://modelleisenbahn.triskell.org/spip.php?mot4" rel="tag"&gt;aiguille&lt;/a&gt;, 
&lt;a href="https://modelleisenbahn.triskell.org/spip.php?mot5" rel="tag"&gt;servo&lt;/a&gt;

		</description>


 <content:encoded>&lt;div class='rss_texte'&gt;&lt;p&gt;Comme pr&#233;sent&#233; dans &#171; &lt;a href='https://modelleisenbahn.triskell.org/spip.php?article34' class=&#034;spip_in&#034;&gt;&#201;tat de l'art&lt;/a&gt; &#187;, il existe de nombreuses fa&#231;ons de monter un servo-moteur en mod&#233;lisme ferroviaire. Voici la solution choisie sur mon r&#233;seau. Il s'agit d'une solution similaire &#224; celle de Pierre mais adapt&#233;e &#224; des micro-servos.&lt;/p&gt;
&lt;h2 class=&#034;spip&#034;&gt;Cahier des charges&lt;/h2&gt;
&lt;p&gt;L'actionneur doit r&#233;pondre &#224; des exigences de mise en &#339;uvre :&lt;/p&gt;
&lt;ul class=&#034;spip&#034; role=&#034;list&#034;&gt;&lt;li&gt; Un encombrement raisonnable. Notamment, il doit &#234;tre possible de mettre deux actionneurs c&#244;te &#224; c&#244;te sur deux voies parall&#232;les avec un entraxe de 26,5mm (entraxe PECO). La hauteur sous la plateforme est moins cruciale dans la mesure o&#249; je me suis d&#233;brouill&#233; pour ne pas avoir d'aiguille au dessus d'une voie.&lt;/li&gt;&lt;li&gt; Un d&#233;montage facile. Notamment le d&#233;montage partiel : d&#233;pose du palonnier, d&#233;pose des contacts de fin de course, d&#233;pose du servo lui-m&#234;me. La d&#233;pose du palonnier est essentielle car glisser la tige dans le trou de la traverse n'est pas des plus commodes.&lt;/li&gt;&lt;li&gt; Un co&#251;t raisonnable, c'est &#224; dire comparable &#224; un actionneur &#224; fil &#224; m&#233;moire.&lt;/li&gt;&lt;li&gt; Les deux orientations doivent &#234;tre possibles. C'est &#224; dire que l'actionneur doit pourvoir se monter dans une position et &#233;galement tourn&#233; de 180&#176;.&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;Il doit aussi satisfaire des exigences fonctionnelles :&lt;/p&gt;
&lt;ul class=&#034;spip&#034; role=&#034;list&#034;&gt;&lt;li&gt; La commutation de l'alimentation du c&#339;ur de l'aiguille. Cette commutation doit &#234;tre faite de mani&#232;re &#224; ce qu'elle ne provoque pas de court-circuit : la commutation doit &#234;tre coh&#233;rente avec les contacts des lames de l'aiguille sur les rails.&lt;/li&gt;&lt;li&gt; Le retour de la position de l'actionneur. Le calculateur qui s'occupe de la commande de l'actionneur pourra ainsi confronter la consigne que l'actionneur doit suivre et sa position effective. Plus de d&#233;tails seront donn&#233;s dans l'article sur les cartes de commande des actionneurs &#224; servo-moteur.&lt;/li&gt;&lt;/ul&gt;&lt;h2 class=&#034;spip&#034;&gt;Satisfaire les exigences de mise en &#339;uvre&lt;/h2&gt;
&lt;p&gt;Le d&#233;montage facile implique une liaison simple entre le servo et la tringle qui passe dans la traverse de l'aiguille. Cela disqualifie les actionneurs o&#249; le mouvement en renvoy&#233; par une tringle interm&#233;diaire.&lt;/p&gt;
&lt;p&gt;La faible largeur ne peut &#234;tre obtenue qu'en positionnant le servo avec sa plus grande dimension dans la direction de la voie.&lt;/p&gt;
&lt;p&gt;La liaison simple concoure aussi &#224; un prix de reviens raisonnable et &#224; un temps de montage court.&lt;/p&gt;
&lt;p&gt;Le co&#251;t et l'encombrement peuvent rester tr&#232;s faible. En effet, les micro-servos sont disponibles &#224; faible co&#251;t, on peut presque parler de consommables. Voir par exemple les &lt;a href=&#034;http://www.hobbyking.com/hobbyking/store/uh_listCategoriesAndProducts.asp?whl=&amp;idCategory=287&amp;v=&amp;sortlist=P&amp;LiPoConfig=&amp;CatSortOrder=asc&#034; class=&#034;spip_out&#034; rel=&#034;external&#034;&gt;servos distribu&#233;s par Hobby King&lt;/a&gt;. Le servo lui m&#234;me revient donc &#224; moins de 2&#8364; pi&#232;ce. &#192; cela il faut ajouter des interrupteurs de fin de course donc le co&#251;t unitaire peut descendre &#224; moins de 50 centimes pi&#232;ce et de la quincaillerie.&lt;/p&gt;
&lt;p&gt;La possibilit&#233; de monter l'actionneur dans un sens ou un autre s'obtient en rendant son empreinte (fixation, sortie de la tringle de commande de l'aiguille) sym&#233;trique.&lt;/p&gt;
&lt;h2 class=&#034;spip&#034;&gt;Satisfaire les exigences fonctionnelles&lt;/h2&gt;
&lt;p&gt;Tout d'abord un mot sur les syst&#232;mes existants en mod&#233;lisme ferroviaire. Ces syst&#232;mes peuvent &#234;tre autonome, &#224; charge pour l'utilisateur d'ajouter une interface permettant d'envoyer des ordres aux servos ou peuvent int&#233;grer une interface num&#233;rique comme le DCC&lt;span class=&#034;spip_note_ref&#034;&gt; [&lt;a href=&#034;#nb4-1&#034; class=&#034;spip_note&#034; rel=&#034;appendix&#034; title=&#034;Bus portant &#224; la fois l'alimentation et les donn&#233;es et utilis&#233; en (&#8230;)&#034; id=&#034;nh4-1&#034;&gt;1&lt;/a&gt;]&lt;/span&gt;. On peut citer :&lt;/p&gt;
&lt;ul class=&#034;spip&#034; role=&#034;list&#034;&gt;&lt;li&gt; Les syst&#232;mes &lt;a href=&#034;http://www.tamvalleydepot.com/&#034; class=&#034;spip_out&#034; rel=&#034;external&#034;&gt;Tam Valley&lt;/a&gt;. Tam Valley propose des &lt;a href=&#034;http://www.tamvalleydepot.com/products/singletservodecoder.html&#034; class=&#034;spip_out&#034; rel=&#034;external&#034;&gt;d&#233;codeurs monoservo&lt;/a&gt;, des &lt;a href=&#034;http://www.tamvalleydepot.com/products/quadservodecoder.html&#034; class=&#034;spip_out&#034; rel=&#034;external&#034;&gt;d&#233;codeurs 4 servos&lt;/a&gt;. Ces deux syst&#232;mes int&#232;grent un d&#233;codeur DCC et ne fonctionnent donc qu'en DCC. En revanche l'&lt;a href=&#034;http://www.tamvalleydepot.com/products/octopusservodriver.html&#034; class=&#034;spip_out&#034; rel=&#034;external&#034;&gt;Octupus III&lt;/a&gt; assure seulement le fonction de pilotage des servos. Il peut &#234;tre connect&#233; &#224; un d&#233;codeur DCC ou bien command&#233; directement par des boutons pour une exploitation dite analogique.&lt;/li&gt;&lt;li&gt; Chez Viessmann, on trouve un &lt;a href=&#034;http://www.viessmann-modell.com/index.php?show=shop&amp;cPath=32&amp;lang=fr&amp;cat=c60_Elektronik%20Mechanik.html&#034; class=&#034;spip_out&#034; rel=&#034;external&#034;&gt;bo&#238;tier de commande monoservo&lt;/a&gt; utilisable en DCC en ajoutant un d&#233;codeur ou en analogique.&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;&#192; ma connaissance, aucun produit commercial pour la commande de servos en mod&#233;lisme ferroviaire n'inclut d'entr&#233;es pour les interrupteurs de fin de course.&lt;/p&gt;
&lt;p&gt;Par cons&#233;quent, la r&#233;trosignalisation de la position des aiguilles est bas&#233;e sur la consigne et non sur l'&#233;tat r&#233;el de la m&#233;canique. Il en d&#233;coule qu'en cas de panne du servo-moteur, l'&#233;tat r&#233;el diff&#232;re de l'&#233;tat connu par l'informatique ou par l'op&#233;rateur avec pour cons&#233;quence des court-circuits sur la commutation du c&#339;ur de l'aiguille&lt;span class=&#034;spip_note_ref&#034;&gt; [&lt;a href=&#034;#nb4-2&#034; class=&#034;spip_note&#034; rel=&#034;appendix&#034; title=&#034;Quand les aiguilles ne prennent pas en charge cette commutation par elles-m&#234;me&#034; id=&#034;nh4-2&#034;&gt;2&lt;/a&gt;]&lt;/span&gt; et des erreurs d'exploitation pouvant conduire &#224; des collisions ou &#224; des d&#233;raillements.&lt;/p&gt;
&lt;p&gt;Il est donc n&#233;cessaire de baser la r&#233;trosignalisation sur la position m&#233;canique des aiguilles. Id&#233;alement le capteur devrait rendre compte de la position des lames ou &#224; d&#233;faut de la traverse. C'est assez difficile &#224; mettre en place, surtout de mani&#232;re invisible. On se contentera donc de la position effective du palonnier du servo au moyen d'interrupteurs de fin de course.&lt;/p&gt;
&lt;h2 class=&#034;spip&#034;&gt;La conception&lt;/h2&gt;
&lt;p&gt;Le servo est donc positionn&#233; de mani&#232;re &#224; ce que le plan du palonnier soit perpendiculaire &#224; la plateforme de voie et parall&#232;le aux traverses.&lt;/p&gt;
&lt;div class='spip_document_95 spip_document spip_documents spip_document_image spip_documents_center spip_document_center spip_document_avec_legende' data-legende-len=&#034;196&#034; data-legende-lenx=&#034;xxx&#034;
&gt;
&lt;figure class=&#034;spip_doc_inner&#034;&gt; &lt;img src='https://modelleisenbahn.triskell.org/local/cache-vignettes/L300xH409/servo_vertical-be9b6.png?1692225210' width='300' height='409' alt='' /&gt;
&lt;figcaption class='spip_doc_legende'&gt; &lt;div class='spip_doc_titre crayon document-titre-95 '&gt;&lt;strong&gt;Montage de l'actionneur
&lt;/strong&gt;&lt;/div&gt; &lt;div class='spip_doc_descriptif crayon document-descriptif-95 '&gt;Cette vue en coupe montre l'actionneur fix&#233; sous la plateforme. En haut la platforme avec le trou de passage, le track-bed et la traverse o&#249; passe la tringle de commande.
&lt;/div&gt; &lt;/figcaption&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;p&gt;Une petite platine d&#233;coup&#233;e dans de la carte plastique de 2 mm supporte le servo. Elle est fix&#233;e sur une corni&#232;re en aluminium de 20 mm x 10 mm. Cette corni&#232;re poss&#232;de un per&#231;age pour laisser passer la tringle et deux trous de fixation. La platine supporte aussi les 4 interrupteurs de fin de course : 2 servent &#224; commuter l'alimentation du c&#339;ur de l'aiguille, les deux autres servent &#224; renvoyer la position &#224; la carte de commande. Les interrupteurs de fin de course sont soud&#233;s sur un petit circuit imprim&#233; qui comporte aussi un bornier pour l'alimentation du c&#339;ur.&lt;/p&gt;
&lt;p&gt;Le sch&#233;ma de ce CI est le suivant :&lt;/p&gt;
&lt;div class='spip_document_96 spip_document spip_documents spip_document_image spip_documents_center spip_document_center spip_document_avec_legende' data-legende-len=&#034;150&#034; data-legende-lenx=&#034;xxx&#034;
&gt;
&lt;figure class=&#034;spip_doc_inner&#034;&gt; &lt;img src='https://modelleisenbahn.triskell.org/local/cache-vignettes/L500xH488/schema_platine_servo-93df4.png?1692342983' width='500' height='488' alt='' /&gt;
&lt;figcaption class='spip_doc_legende'&gt; &lt;div class='spip_doc_titre crayon document-titre-96 '&gt;&lt;strong&gt;Sch&#233;ma de la platine
&lt;/strong&gt;&lt;/div&gt; &lt;div class='spip_doc_descriptif crayon document-descriptif-96 '&gt;La platine supporte les 4 interrupteurs de fin de course et un bornier pour le raccordement des rails et du c&#339;ur de l'aiguille.
&lt;/div&gt; &lt;/figcaption&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;p&gt;La prise d'origine du servo est coup&#233;e et les fils sont directement soud&#233;s sur le CI. Une nappe De 5 fils (5,3V, PWM, Fin de Course Horaire, GND, Fin de Course Trigo) raccorde la platine &#224; la carte de commande.&lt;/p&gt;
&lt;div class='spip_document_97 spip_document spip_documents spip_document_image spip_documents_center spip_document_center spip_document_avec_legende' data-legende-len=&#034;26&#034; data-legende-lenx=&#034;&#034;
&gt;
&lt;figure class=&#034;spip_doc_inner&#034;&gt; &lt;img src='https://modelleisenbahn.triskell.org/local/cache-vignettes/L430xH317/ci_servo-c4678.png?1692225211' width='430' height='317' alt='' /&gt;
&lt;figcaption class='spip_doc_legende'&gt; &lt;div class='spip_doc_titre crayon document-titre-97 '&gt;&lt;strong&gt;Typon du circuit imprim&#233;
&lt;/strong&gt;&lt;/div&gt; &lt;/figcaption&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;p&gt;Le CI est fix&#233; sur la platine au moyen de 2 vis de M2x20mm qui passent par les trous de fixation des interrupteurs de fin de course. La platine est perc&#233;e &#224; 4mm de mani&#232;re &#224; pouvoir ajuster les fins de course par rapport au palonnier.&lt;/p&gt;
&lt;div class='spip_document_98 spip_document spip_documents spip_document_image spip_documents_center spip_document_center spip_document_avec_legende' data-legende-len=&#034;25&#034; data-legende-lenx=&#034;&#034;
&gt;
&lt;figure class=&#034;spip_doc_inner&#034;&gt; &lt;a href='https://modelleisenbahn.triskell.org/IMG/jpg/actionneur_aiguille.jpg' class=&#034;spip_doc_lien mediabox&#034; type=&#034;image/jpeg&#034;&gt; &lt;img src='https://modelleisenbahn.triskell.org/local/cache-vignettes/L500xH307/actionneur_aiguille-85e0c.jpg?1692342983' width='500' height='307' alt='' /&gt;&lt;/a&gt;
&lt;figcaption class='spip_doc_legende'&gt; &lt;div class='spip_doc_titre crayon document-titre-98 '&gt;&lt;strong&gt;L'actionneur d'aiguille
&lt;/strong&gt;&lt;/div&gt; &lt;/figcaption&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;p&gt;Pour appuyer sur deux fins de course simultan&#233;ment, il est n&#233;cessaire de munir le palonnier de deux tiges aux extr&#233;mit&#233;s. Ces tiges sont r&#233;alis&#233;es avec des vis et des &#233;crous.&lt;/p&gt;
&lt;p&gt;L'actionneur est assembl&#233; exclusivement avec des vis, rondelles et &#233;crous. Tout ou presque est d&#233;montable.&lt;/p&gt;
&lt;h2 class=&#034;spip&#034;&gt;Fixation sous la plateforme&lt;/h2&gt;
&lt;p&gt;L'actionneur est fix&#233; au moyen de 2 vis de 3mm &#224; t&#234;te frais&#233;e. On perce la plateforme &#224; &#233;gale distance de part et d'autre de la voie (&#233;cartement de 30mm). &#192; cet effet, un gabarit a &#233;t&#233; fabriqu&#233;. Deux &#233;crous tiennent les vis par dessous. L'actionneur est ensuite boulonn&#233; en place.&lt;/p&gt;
&lt;h2 class=&#034;spip&#034;&gt;Co&#251;t d'un actionneur&lt;/h2&gt;
&lt;p&gt;Les 42 actionneurs pr&#233;vus pour le r&#233;seau n&#233;cessitent les composants suivants :&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Quincaillerie&lt;/strong&gt;&lt;/p&gt;
&lt;ul class=&#034;spip&#034; role=&#034;list&#034;&gt;&lt;li&gt; Corni&#232;re aluminium brut 20 mm x 10 mm en 2 m : 8,65&#8364; (Castorama) ;&lt;/li&gt;&lt;li&gt; Plaques de styr&#232;ne blanche opaque Evergreen au format 200x530 mm &#233;paisseur 2,00 mm / 2 plaques : 15,50&#8364; (Micro-mod&#232;les), il restera du rab pour les b&#226;timents ;&lt;/li&gt;&lt;li&gt; Corde &#224; piano de 0,5mm, 3m : 0,90 (Micro-mod&#232;les) ;&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Visserie&lt;/strong&gt;&lt;br class='autobr' /&gt;
Fixation des actionneurs sous la plateforme :&lt;/p&gt;
&lt;ul class=&#034;spip&#034; role=&#034;list&#034;&gt;&lt;li&gt; 200 vis &#224; t&#234;te frais&#233;e de M3x16mm : 2,15&#8364; (TME)&lt;/li&gt;&lt;li&gt; 200 &#233;crous M3 : 1,14&#8364; (TME)&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;Fixation du servo sur la platine et de la platine sur la corni&#232;re :&lt;/p&gt;
&lt;ul class=&#034;spip&#034; role=&#034;list&#034;&gt;&lt;li&gt; 100 vis M2x6 : 0,8&#8364; (TME)&lt;/li&gt;&lt;li&gt; 100 vis M2x8 : 0,85&#8364; (TME&lt;/li&gt;&lt;li&gt; 200 &#233;crous M2 : 1,5&#8364; (TME)&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;Syst&#232;me d'appui sur les fins de course et de fixation de la tringle de commande&lt;/p&gt;
&lt;ul class=&#034;spip&#034; role=&#034;list&#034;&gt;&lt;li&gt; 100 vis M2x12 : 0,7&#8364; (TME)&lt;/li&gt;&lt;li&gt; 100 vis M2x10 : 0,6&#8364; (TME)&lt;/li&gt;&lt;li&gt; 450 &#233;crous M2 : 3&#8364; (TME)&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Composants&lt;/strong&gt;&lt;/p&gt;
&lt;ul class=&#034;spip&#034; role=&#034;list&#034;&gt;&lt;li&gt; 168 interrupteurs de fin de course miniatures (1A) : 40&#8364;10 (TME)&lt;/li&gt;&lt;li&gt; 42 borniers 3 points, pas 3,5mm : 11&#8364;10 (TME)&lt;/li&gt;&lt;li&gt; 42 servo-moteurs HK15178 : 77&#8364;70 (HobbyKing)&lt;/li&gt;&lt;li&gt; 30m de c&#226;ble en nappe 10 conducteurs : 11&#8364; (TME)&lt;/li&gt;&lt;li&gt; 42 connecteurs pour cosses &#224; sertir : 3&#8364;90 (TME)&lt;/li&gt;&lt;li&gt; 500 cosses pour les connecteur : 7&#8364;33 (TME)&lt;/li&gt;&lt;li&gt; Circuit imprim&#233; &#224; graver : 5&#8364;50 (TME)&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;Soit une somme totale d'environ 190&#8364; et 4&#8364;50 par actionneur. Qui dit mieux ?&lt;/p&gt;
&lt;h2 class=&#034;spip&#034;&gt;R&#233;alisation&lt;/h2&gt;
&lt;p&gt;Le prototype a &#233;t&#233; test&#233; avec succ&#232;s. Ces tests ont permis de d&#233;terminer la diam&#232;tre de la tringle (corde &#224; piano de 0,5mm de &#216;), l'&#233;cartement entre la corni&#232;re et la plateforme (l'&#233;paisseur des &#233;crous est suffisantes) et le r&#233;glage des fins de course. Les 42 corni&#232;res n&#233;cessaires ont &#233;t&#233; d&#233;coup&#233;es et perc&#233;es. 6 des 9 exemplaires destin&#233;s &#224; &#233;quiper la gare ont &#233;t&#233; assembl&#233;s. Les efforts portent maintenant sur la carte de commande qui fera l'objet d'un prochain billet.&lt;/p&gt;
&lt;div class='spip_document_99 spip_document spip_documents spip_document_image spip_documents_center spip_document_center spip_document_avec_legende' data-legende-len=&#034;36&#034; data-legende-lenx=&#034;x&#034;
&gt;
&lt;figure class=&#034;spip_doc_inner&#034;&gt; &lt;a href='https://modelleisenbahn.triskell.org/IMG/jpg/actionneurs_aiguille.jpg' class=&#034;spip_doc_lien mediabox&#034; type=&#034;image/jpeg&#034;&gt; &lt;img src='https://modelleisenbahn.triskell.org/local/cache-vignettes/L500xH248/actionneurs_aiguille-f1e6e.jpg?1692342983' width='500' height='248' alt='' /&gt;&lt;/a&gt;
&lt;figcaption class='spip_doc_legende'&gt; &lt;div class='spip_doc_titre crayon document-titre-99 '&gt;&lt;strong&gt;La fabrication en s&#233;rie a commenc&#233;
&lt;/strong&gt;&lt;/div&gt; &lt;/figcaption&gt;&lt;/figure&gt;
&lt;/div&gt;&lt;/div&gt;
		&lt;hr /&gt;
		&lt;div class='rss_notes'&gt;&lt;div id=&#034;nb4-1&#034;&gt;
&lt;p&gt;&lt;span class=&#034;spip_note_ref&#034;&gt;[&lt;a href=&#034;#nh4-1&#034; class=&#034;spip_note&#034; title=&#034;Notes 4-1&#034; rev=&#034;appendix&#034;&gt;1&lt;/a&gt;] &lt;/span&gt;Bus portant &#224; la fois l'alimentation et les donn&#233;es et utilis&#233; en exploitation num&#233;rique&lt;/p&gt;
&lt;/div&gt;&lt;div id=&#034;nb4-2&#034;&gt;
&lt;p&gt;&lt;span class=&#034;spip_note_ref&#034;&gt;[&lt;a href=&#034;#nh4-2&#034; class=&#034;spip_note&#034; title=&#034;Notes 4-2&#034; rev=&#034;appendix&#034;&gt;2&lt;/a&gt;] &lt;/span&gt;Quand les aiguilles ne prennent pas en charge cette commutation par elles-m&#234;me&lt;/p&gt;
&lt;/div&gt;&lt;/div&gt;
		
		</content:encoded>


		

	</item>



</channel>

</rss>
