Lampe Web

Il y a quelque temps, j’avais promis à une certaine personne que je réaliserais ma propre lampe de type Living Colors. Seulement, contrôler la couleur ambiante grâce à une télécommande c’est bien, mais je voulais pouvoir le faire depuis un PC ou tout autre appareil connecté.

Dès le début, je pensais réaliser un montage autour d’une carte FOX LX832 développée par la société italienne Acme Systems. La carte FOX est un système embarqué complet basé sur un processeur Etrax 100LX construit par Axis. Elle permet de faire tourner un système GNU/Linux (noyau 2.6) et propose une multitude d’interfaces (USB, i2c, SPI, UART, Ethernet, GPIO…) Tout ça pour un poids de moins de 40g.

Acme Systems FOX LX832

Selon un premier schéma, la carte FOX héberge un serveur TCP à l’écoute d’un client et pilote, selon les réglages de l’utilisateur, trois LEDs: une rouge, une verte et une bleue.

L’interface utilisateur

Au départ je comptais coder l’interface en C++ à l’aide d’un framework tel que GTK ou QT. Après réflexion, il apparaissait plus judicieux de réaliser le client en flash: le résultat est directement utilisable sur de nombreux OS et architectures, l’aspect graphique est complètement personnalisable et, le plus important: le composant peut être inséré dans une simple page HTML. L’interface de contrôle est alors accessible de n’importe où avec un simple navigateur web (pour peu que le matériel utilisé supporte Flash).

L’espace colorimétrique le plus adapté à ce genre d’application semble être le HSV. La première chose que l’on cherche à régler est la teinte de la lumière (hue), puis on peut ajuster le niveau de luminosité (value) et la saturation des couleurs.

Deux composants de type "slider" sont présents pour définir le niveau de saturation et de luminosité. Pour ce qui est de la teinte, il n’existe pas de composant prédéfini satisfaisant. Avec un peu de  code ActionScript, on peut créer une roue de sélection de teinte avec curseur (j’ai honteusement copié le design de la Living Colors) et par la même occasion, ajouter au centre une prévisualisation de la couleur sélectionnée.

Interface de contrôle

A chaque modification d’un paramètre, les valeurs des composantes rouge, verte et bleue correspondantes sont calculées. Cette conversion est réalisée par le client qui dispose d’une capacité de calcul supérieure à celle du système embarqué.

Restait à faire communiquer l’application Flash avec la carte FOX. Une solution consiste à envoyer des requêtes HTTP classiques. Cependant, ce type de connexion n’est pas persistant: un nouveau socket TCP doit être créé à chaque échange de données. Or, dans le cadre d’une application "temps réel", il est important de réduire un maximum les temps de latence lors de communications entre les différents éléments. Heureusement, il est également possible d’utiliser la classe XMLSocket qui permet l’envoi/réception de fichiers XML sur un socket TCP persistant. (Ce n’est qu’après avoir terminé que je me suis aperçu qu’il existait une classe Socket qui permet de se passer du formatage XML)

Le format utilisé pour envoyer les données à la platine est réduit au strict minimum: #RRVVBB suivi du caractère de nouvelle ligne et du caractère nul (où RR, VV, BB représentent les valeurs des composantes rouge, verte et bleue en notation hexadécimale) L’utilisation d’un caractère en première position (ici #) assure par la suite de pouvoir étendre le protocole avec de nouvelles commandes. La notation hexadécimale est préférée au format binaire afin de pouvoir communiquer plus facilement en mode texte avec le serveur (avec netcat par exemple)

Dernier détail: depuis la version 9.0.124.0 de Flash, l’utilisation d’un fichier de régulation d’accès est imposée. Avant toute connexion à un socket, le client tente de se connecter au port 843 du serveur et envoie une requête de fichier policy. Il s’attend alors à recevoir en retour un fichier XML, contenant une description des autorisations d’accès ,suivi d’un caractère nul. Si le serveur ne répond pas sur ce port, il tente la même procédure sur le port distant du socket.

Il sera donc nécessaire de mettre en place un second serveur sur la carte FOX qui aura pour unique rôle de répondre à ce type de requête. Un seul serveur pourrait suffire mais j’ai préféré dissocier les services: d’autres serveurs de clients flash pourraient par la suite être hébergés sur le système, ils partageraient alors un seul et unique serveur de régulation.

Une fois le projet Flash compilé, le fichier swf obtenu est intégré dans une page HTML. La carte FOX héberge un serveur HTTP boa qui, par défaut, sert à transférer des fichiers sur le système. Les transferts étant également possibles en FTP ou SCP,  le fichier de configuration de boa a été modifié pour affecter le nouveau fichier HTML en page d’accueil. De base, le répertoire racine du serveur HTTP est situé sur une partition montée en lecture seule, il a donc été redirigé vers un répertoire localisé sur une partition accessible en écriture.

Code ActionScript du client

Le serveur

Pour permettre une compilation croisée du noyau Linux et des applications destinés à la carte LX832, le phrozen SDK de Acme Systems a été installé sur un distribution Gentoo.

Le système par défaut présent sur la carte ne convenant pas, il a fallu dans un premier temps recompiler le noyau Linux après avoir avoir modifié certaines options puis flasher la nouvelle image. En effet, comme je le verrai plus tard, le support du bus i2c est indispensable. Seulement, le support du module RTC est activé par défaut dans l’image d’usine et, je ne sais pour quelle raison, empêche le bon fonctionnement des autres périphériques i2c.

La première application C s’exécutant sur la platine a pour rôle la distribution du fichier de régulation, elle effectue les opérations suivantes: un socket est créé, rattaché au port local 843 et mis en attente de clients. A chaque connexion , un thread est créé pour renvoyer le contenu du fichier policy stocké sur le système suivi d’un caractère nul. Le socket  est ensuite fermé. Le fichier de régulation est le suivant:

<cross-domain-policy>
<allow-access-from domain="*" to-ports="7777" secure="false" />
</cross-domain-policy>

Petit détail: pour que ce programme puisse fonctionner correctement sur la cible, il faut lors de l’édition des liens que la librairie pthread soit liée en statique.

Le second programme a pour rôle la réception des trames de couleurs provenant du client Flash et la commande des LEDs. Il suit le même principe que le premier: un socket est à l’écoute du port 7777. Lors d’une connexion client, un thread est créé qui reçoit puis décode le message au format #RRVVBB. Le fait que la gestion des connexions soit multi-threadée permet à plusieurs clients de contrôler la lampe en même temps et évite qu’une session non déconnectée bloque les autres.

La question qui se pose alors est la suivante: comment faire varier individuellement la luminosité des 3 LEDs à partir de la platine? La solution qui s’impose de par sa simplicité et sa linéarité est une commande en PWM. Seulement, contrairement à sa petite sœur la FOX G20, la LX832 ne dispose pas de ce type de sortie.

J’ai donc d’abord essayé d’émuler des sorties PWM logicielles en utilisant un port GPIO. Des appels systèmes sont implémentés dans le système Linux embarqué: ils permettent de fixer l’état d’une sortie et ainsi d’obtenir des signaux carrés dont la fréquence peut atteindre les 150KHz. A l’aide de temporisations entre les transitions vers l’état haut/bas, on peut faire varier le rapport cyclique du signal.

En pratique, cette implémentation fonctionne uniquement en monotâche. En effet, tant que le thread qui gère le PWM monopolise à lui seul le temps processeur, tout se passe bien. A partir du moment où il se produit des changements de contextes, il devient difficile de générer un signal correct: le noyau se base (comme sur PC) sur un timer de fréquence 100Hz pour scheduler les threads. Cela veut dire que lors du switch vers un autre thread, il faudra attendre jusqu’à 10ms pour revenir à notre routine, période pendant laquelle le signal est bloqué sur un même état.

Une option de compilation du noyau permet bien d’augmenter la valeur de la fréquence de ce timer mais la mise en place resterait trop complexe, sans compter qu’il faut gérer 3 signaux simultanément.

Je me suis donc tourné vers des circuits PWM spécialisés utilisant le bus i2c. Ces circuits sont soit trop couteux pour cette utilisation, soit indisponibles.

J’ai au final fait le choix d’un microcontrôleur ATMEL AVR. On y gagne en flexibilité (je décide de la manière dont sont échangées les données entre la platine et le périphérique) au détriment d’une mise en place légèrement plus complexe (il faudra également programmer l’AVR). En ce qui concerne le modèle, mon choix s’est porté sur l’ATMEGA8: il dispose de trois canaux Fast PWM, d’une interface i2c (désigné TWI par Atmel) et il se programme en C (il s’est avéré après coup que le modèle ATTINY2313 aurait aussi bien fait l’affaire).

Le schéma final ressemble donc à ceci:

Schéma global

Les communications entre la carte et le microcontrôleur se feront sur le bus i2c. Ce mode de communication ne nécessite que deux lignes (horloge et données) et atteint en mode normal des débits de 100kb/s. La platine joue le rôle de maître et l’AVR celui d’esclave. Un seul mode sera utilisé dans ce contexte: maître émetteur, esclave récepteur. Le maître envoie d’abord un bit de start sur le bus, suivi de l’adresse de l’esclave sur 7bits et d’un bit à 0 indiquant une demande d’écriture. Après cela, plusieurs octets peuvent être émis, acquittés un à un par l’esclave jusqu’à l’envoi d’un bit de stop par le maître.

Dans le cas de notre application, le serveur envoie des séries de trois octets à la cible correspondant dans l’ordre aux composantes rouge, verte et bleue. Sur la carte FOX, le bus i2c est géré par le noyau. L’accès en espace utilisateur se fait à l’aide de l’appel système ioctl. Afin d’éviter tout accès simultané au bus i2c par plusieurs threads, un mutex protège les sections où des données sont envoyées.

Exemple de message envoyé depuis la platine vers l’AVR sur le bus i2c

Code source du serveur de policyCode source du serveur de commande

Le microcontrôleur

Le programme C exécuté par l’AVR a pour rôle de réceptionner le niveau de luminosité souhaité pour chaque  LED depuis le bus i2c et de commander les sorties PWM.

Les pins PB1, PB2 et PB3 sont d’abord configurés en sorties. Les trois canaux PWM rattachés sont configurés en mode fast et activés. Le bus TWI est ensuite configuré en esclave et l’adresse du périphérique est fixé à ‘0010101’ ( j’ai cherché à utiliser une adresse ne correspondant à aucun périphérique connu). Un traitement en boucle scrute le flag de réception d’un message sur le bus et affecte chacun des trois octets reçus au canal PWM correspondant.

Les trois signaux PWM en sortie de l’AVR

Le programme est compilé sous Windows en utilisant l’IDE AVR Studio associé à WinAVR (version Windows de avr-gcc). Le fichier binaire obtenu est transféré dans la mémoire flash de l’ATMEGA8 à l’aide d’un programmateur ISP USB trouvé sur ebay pour une quinzaine d’€uros.

Programmateur ISP USB

Pour simplifier le montage, le microcontrôleur est alimenté en 3.3V par la carte FOX. Cette solution assure aussi une compatibilité des niveaux logiques des communications en i2c entre la platine et l’AVR.

Même si chaque sortie de l’ATMEGA8 est capable de fournir ou absorber jusqu’à 40 mA, ça ne suffit pas pour alimenter directement des LEDs de puissance. Un circuit de commande doit être intercalé.

Code source du programme de l’AVR

Etage de "puissance"

Les LEDs utilisées sont de type haute luminosité et peuvent atteindre une intensité lumineuse de 50 candelas. Leur consommation varie de 50 mA pour le bleu à 70 mA pour le rouge. Le montage contient trois groupes de deux LEDs. L’ensemble produit au maximum un éclairement équivalent à une ampoule de 20W, ce qui est suffisant pour une lampe d’ambiance. L’inconvénient majeur de ce modèle de LED est son faible angle d’éclairage: 50% du flux lumineux est émis à un angle inférieur à 15°. Il est donc préférable d’utiliser un diffuseur de lumière.

Chaque groupe de LEDs est alimenté par une alimentation secondaire de 9V et est commandé par un transistor NPN fonctionnant en commutation. Les sorties PWM de l’AVR atteignent des fréquences de plusieurs dizaines de kilohertz, le modèle BC337 suffit amplement..

Circuit de commande des LEDs

Reste la question du diffuseur. Après plusieurs essais, le modèle qui convient le mieux est étonnement un gobelet en carton de McDonald’s. Le carton blanc est assez épais et le couvercle en plastique mélange bien les couleurs sans trop atténuer la lumière.

Le "diffuseur"

Et après?

Il reste encore pleins de choses à améliorer sur cette lampe: augmenter le nombre de LEDs pour agmenter l’intensité lumineuse, utiliser des contrôleurs de tension pour améliorer la stabilité de l’alimentation des LEDs ou encore ajouter de nouveaux modes de commande  (cycle de couleurs, stroboscope, présélections…). Une autre idée serait de miniaturiser le montage en utilisant un unique microcontrôleur qui jouerait à la fois le rôle de l’ATMEGA8 et celui de la carte FOX.

About these ads

9 thoughts on “Lampe Web

  1. Ping : Modes lampe Web | Gibus

  2. Ping : Lampe Android | Gibus

  3. Ping : Impromptu lamp runs Linux - Hack a Day

  4. Ping : Impromptu lamp runs Linux » Geko Geek

  5. Ping : Impromptu lamp runs Linux « HuntAll

  6. Ping : Impromptu lamp runs Linux | ro-Stire

  7. Ping : Impromptu lamp runs Linux | CisforComputers

  8. Ping : Impromptu lamp runs Linux -Via Hack a Day | OverView-Effect

Laisser un commentaire

Entrez vos coordonnées ci-dessous ou cliquez sur une icône pour vous connecter:

Logo WordPress.com

Vous commentez à l'aide de votre compte WordPress.com. Déconnexion / Changer )

Image Twitter

Vous commentez à l'aide de votre compte Twitter. Déconnexion / Changer )

Photo Facebook

Vous commentez à l'aide de votre compte Facebook. Déconnexion / Changer )

Photo Google+

Vous commentez à l'aide de votre compte Google+. Déconnexion / Changer )

Connexion à %s