Programmation Arduino en ligne de commande

Aujourd\’hui, c\’est un nouveau rédacteur qui fait son entrée sur ce blog! Fabien nous propose un article sur la programmation des cartes Arduino depuis le terminal.
À propos de l\’auteur : Fabien Danieau est doctorant à Rennes, entre l\’INRIA et Technicolor. Titulaire d\’un diplôme d\’Ingénieur en Cognitique, ses travaux portent actuellement sur l\’application des interfaces haptiques pour le multimédia.

 

\"Arduino\"Arduino est une plateforme de prototypage électronique. Cela se présente sous la forme d\’une petite carte, avec un circuit imprimé et un microprocesseur, qui permet de réaliser très facilement et très rapidement des montages électroniques. De plus un éditeur simplissime est fourni afin que les débutants en programmation puisse s\’adonner aux joies de l\’électronique. Un langage basé sur le C++ est proposé, les programmes sont appelés \ »sketch\ ». Pour couronner le tout, hardware et software sont tous les deux open source. Ainsi cette plateforme connaît un véritable engouement et les projets fleurissent sur la toile.

La force de ce produit est donc sa simplicité. L\’environnement de programmation y contribue en grande partie. Seules quelques lignes de codes suffisent à allumer ses premières LEDs. Cependant cette simplicité devient vite une limite lorsque l\’on veut développer de plus gros projets. Gérer un code compliqué avec beaucoup de dépendances peut devenir un vrai casse-tête. De plus l\’éditeur n\’est encore qu\’une version alpha (0022 à l\’écriture de ce billet) et n\’est donc pas exempt de bugs. Sur ma machine, la carte n\’est pas toujours détectée lors de son branchement à un port USB. De ce fait il m\’est parfois impossible de charger un programme…
Bref pour diverses raisons on peut vouloir comprendre ce qui se passe derrière l\’éditeur. Ne serait-ce que pour être capable d\’utiliser un autre environnement de programmation. Nous allons donc voir comment compiler et charger un sketch à la main. Suite à cela, diverses alternatives à l\’environnement de développement fourni par Arduino seront proposées.

Pré-requis

Une grande partie des explications seront bâties sur l\’exemple suivant. Il est volontairement basique, les deux premiers tutos du site Arduino suffisent à le comprendre (cf. tuto Blink et tuto DigitalReadSerial). La seule chose que fait ce code est d\’allumer la LED liée à la pin 13 et d\’écrire \ »Starting\ » puis \ »Running\ » toutes les secondes et demi sur la sortie série.

int ledPin = 13;

void setup(){
pinMode(ledPin, OUTPUT);
Serial.begin(115200);
Serial.println(\"Starting\");
}

void loop(){
digitalWrite(ledPin, HIGH);
delay(1000);
digitalWrite(ledPin, LOW);
delay(500);
Serial.println(\"Running\");
}

Pour la suite de l\’article nous supposerons que ce code fonctionne sans soucis sur la carte en utilisant l\’éditeur Arduino. Nous appellerons ce sketch \ »blink.pde\ ». Vous devriez obtenir un résultat similaire à celui-ci.

\"\"

A titre indicatif l\’ensemble des manipulations présentées ont été effectué sur une distribution Linux Debian Squeeze 64bits, une carte Arduino Uno SMD (microprocesseur atmel mega 328p) et l\’éditeur en version 0022 (téléchargé depuis le site officiel. La version dans les dépots de Debian est obsolète).

Le secret de l\’IDE Arduino

L\’idée de ce billet est de compiler l\’exemple précédent sans passer par l\’éditeur d\’Arduino. Une première étape consiste à demander à l\’éditeur de nous expliquer ce qu\’il fait lorsqu\’il compile. En faisant cela nous pourrons comprendre les mécanismes sous-jacents à la compilation et au chargement de sketchs sur la carte.
Par défaut l\’éditeur n\’est pas très loquace. Pour le rendre un peu plus bavard il faut modifier quelques options dans les préférences. Ouvrez le fichier de préférences avec votre éditeur favori.

gedit .arduino/preferences.txt

Puis rajoutez les deux options suivantes à la fin du fichier.

build.verbose=true
upload.verbose=true

Une fois ceci fait, lancez une nouvelle compilation du programme. Tout le processus de compilation est détaillé! Quelque chose dans ce goût là devrait apparaître.
\"\"

La deuxième option que nous avons rajouté sert à afficher le même genre d\’information mais lors du chargement (upload) du programme sur la carte.

Si on regarde ce que nous affiche l\’éditeur lors de la compilation on peut voir des commandes du style \ »avr-gcc\ », \ »avr-ar\ » ou encore \ »avr-objcopy\ ». La plateforme Arduino repose en fait sur la solution open source avrdude qui permet de communiquer avec des microprocesseurs atmel. Il suffit donc d\’utiliser directement cet outil pour programmer notre carte!
Avant de se lancer dans le détail du processus de compilation, il faut d\’abord installer avrdude. Normalement un simple apt-get devrait suffire chez les utilisateurs de Debian et autres distributions dérivées.

sudo apt-get install avrdude

Processus de compilation

Conversion du sketch en fichier cpp

Une chose qui surprend de prime abord est que notre fichier blink.pde n\’apparait nulle part dans les infos affichées par l\’éditeur. Par contre nous avons un fichier blink.cpp qui est compilé. En réalité avrdude permet de compiler des fichiers c/c++, les sketch ne sont qu\’en fait une surcouche créés par Arduino pour simplifier l\’écriture de code. Avrdude ne comprend pas ce \ »langage\ » donc une première chose que fait l\’éditeur est de traduire le sketch en fichier c++. Cela est très simple en pratique, il n\’y a pas de grande différences. L\’éditeur ne fait qu\’ajouter un \ »include\ » et les en-têtes des fonctions utilisées dans le sketch. Ce qui donne le fichier \ »blink.cpp\ ».

#include \"WProgram.h\"
void setup();
void loop();
//plus le reste du code affiché plus haut

Le fichier \ »WProgram.h\ » ajouté est fourni avec l\’éditeur. On peut le trouver dans le répertoire d\’installation ( quelque chose du genre arduino-0022/hardware/arduino/cores/arduino/) . Ce dossier contient tous les fichiers nécessaires à la création d\’un programme compréhensible par la carte arduino et sont compilés à chaque fois que l\’on compile un sketch.

Compilation des sources

Pour créer notre programme, la première étape consiste à compiler notre fichier \ »blink.cpp\ ». Cela se fait par la commande suivante.

avr-g++ -c -g -Os -w -fno-exceptions -ffunction-sections -fdata-sections -mmcu=atmega328p -DF_CPU=16000000L -DARDUINO=22 -I /home/fabien/Apps/arduino-0022/hardware/arduino/cores/arduino/ -o blink.o blink.cpp

Il vous faudra bien sûr adapter cette commande à votre configuration. Notamment après le \ »-I\ » où vous devez indiquez le chemin vers le répertoire d\’installation de l\’éditeur arduino. Nous n\’irons pas plus loin dans l\’explication des différents arguments. Ce degré de détails n\’est pas forcément l\’objet de ce billet et je ne suis pas non plus familier avec toutes les options. A l\’issue de cette commande vous devriez obtenir le fichier \ »blink.o\ ».
Le travail n\’est pas fini, vous avez sans doute remarqué que l\’éditeur compile beaucoup plus de fichiers. Comme je l\’ai dit plus haut, toutes les sources situées avec le fichier \ »WProgram.h\ » sont compilées. C\’est ce que nous allons faire à présent.
Pour plus de clarté nous allons faire les prochaines manipulations dans un sous-dossier que j’appellerai \ »core\ ».

mkdir core
cd core

Ensuite la commande de compilation reste la même qu\’au dessus. Par exemple pour le fichier \ »Print.cpp\ »:

avr-g++ -c -g -Os -w -fno-exceptions -ffunction-sections -fdata-sections -mmcu=atmega328p -DF_CPU=16000000L -DARDUINO=22 -I /home/fabien/Apps/arduino-0022/hardware/arduino/cores/arduino/ -o Print.o /home/fabien/Apps/arduino-0022/hardware/arduino/cores/arduino/Print.cpp

A noter que certaines sources sont en C. Il faut donc appeler avr-gcc cette fois-ci et enlever \ »-ffunction-sections\ ». Par exemple pour le fichier \ »wiring.c\ »:

avr-gcc -c -g -Os -w -ffunction-sections -fdata-sections -mmcu=atmega328p -DF_CPU=16000000L -DARDUINO=22 -I /home/fabien/Apps/arduino-0022/hardware/arduino/cores/arduino/ -o wiring.o /home/fabien/Apps/arduino-0022/hardware/arduino/cores/arduino/wiring.c

En tout il y a 13 sources à compiler et autant de \ ».o\ » à créer. Ce n\’est pas l\’étape la plus rigolote c\’est sûr. Elle est intéressante à faire une fois pour bien comprendre le processus. Nous verrons à la fin les outils qui font tout pour nous :).
La dernière étape de la compilation est la création de la librairie. Nous sommes toujours dans notre dossier \ »core\ » avec nos 13 \ ».o\ ». Il suffit d\’appeler \ »avr-ar\ » pour tous les compiler en une librairie.

avr-ar rcsv core.a *.o

Et voilà le travail, la librairie \ »core.a\ » devrait être présente dans votre dossier. On remarque que l\’éditeur refait toute la procédure de création de la librairie à chaque compilation. Pourtant l\’édition d\’un sketch ne modifie que \ »blink.pde\ » et donc \ »blink.cpp\ ». On peut se demander si cela à un réel intérêt…

linkage et creation de l\’\ »executable\ »

La prochaine étape vise à lier notre programme compilé, \ »blink.o\ » avec la librairie \ »core.a\ ». Nous remontons d\’un niveau (\ »cd ..\ ») pour nous retrouver dans le dossier contenant ledit \ »blink.o\ » et le dossier \ »core\ ». La commande suivante fera l\’affaire.

avr-gcc -Os -Wl,--gc-sections -mmcu=atmega328p -o blink.elf blink.o ./core/core.a -L core -lm

Le fichier \ »blink.elf\ » devrait apparaître.
Nous touchons à la fin. La dernière étape vise à créer l\’équivalent d\’un exécutable que l\’on pourra charger sur la carte. La création se fait ainsi.

avr-objcopy -O ihex -R .eeprom blink.elf blink.hex

Ca y est tout est compilé! Le fichier \ »blink.hex\ » nouvellement créé est le signe de notre réussite.

Upload

Allez c\’est bientôt fini. Nous allons maintenant charger ce programme sur la carte. Branchons la sur un port usb. Et lançons une dernière commande.

avrdude -v -p m328p -P /dev/ttyACM0 -b115200 -c arduino -U flash:w:blink.hex

Chez vous il faut indiquer le port correspondant à votre carte à la place du /dev/ttyACM0. Si vous utilisez une arduino Uno ça devrait être pareil. Le nombre 115200 correspond à la vitesse de communication entre la carte et le pc fixée à 115200 bauds, et doit être le même que celui indiqué dans le code \ »blink.pde\ ».
Si tout se passe bien la LED liée à la pin 13 doit clignoté à l\’issue du chargement sur la carte. Tout s\’est bien passé, vous avez réussi à compiler votre premier programme à la main!

Communication série

C\’est bien beau tout ça, mais vous allez me demander où s\’affichent les fameux messages \ »Starting\ » et \ »Running\ ». Avec l\’éditeur il suffisait d\’afficher le moniteur, mais maintenant? Avons-nous perdu un outil dans la bataille?
Pas du tout n\’ayez crainte. Nous allons utiliser une alternative appelé \ »screen\ ». Elle permet entre autres d\’émuler un terminal. En lançant la commande suivante dans une console vous devrez voir les messages que l\’on croyait perdus.

screen /dev/ttyACM0 115200

Vous trouverez cet outil dans les dépôts s\’il n\’est pas installé. Le résultat doit approcher celui-ci:

\"\"

Conclusion et alternatives

Voilà nous savons maintenant compiler un programme pour Arduino à la main. Cependant le processus complet est un peu fastidieux. Il est intéressant de le faire une fois pour bien comprendre le mécanisme mais ce n\’est pas vraiment pratique pour une utilisation régulière.
Par contre en connaissant la chaine de compilation utilisant avrdude, rien ne nous empèche de l\’adapter et de l\’utiliser avec notre environnement de développement préféré. Plusieurs solutions existent déjà et vous permettent de compiler un sketch via un makefile, CMake, Scons or encore sous Eclipse.

Réferences

11 réflexions au sujet de « Programmation Arduino en ligne de commande »

  1. Excellent merci !
    J’avais commencer à chercher comment faire ça et finalement remis la chose à plus tard… Tu me simplifies grandement la tache :-)
    Je trouve l’IDE Arduino plutôt bien fait mais si je peux utiliser mon éditeur de texte favoris c’est encore mieux.
    A+

  2. Chez moi, (Mac OS X 10.6.6 et Arduino 0022)
    l’instruction « compile.verbose=true » ne mache pas,
    c’est « build.verbose=true » qu’il faut mettre pour avoir les informations de compilation dans l’IDE Arduino.

    « Le nombre 115200 correspond au bitrate, c’est à dire la vitesse de communication entre la carte et le pc, et doit être le même que celui indiqué dans le code « blink.pde ». »
    Erreur il s’agit ici de la vitesse de communication avec le bootloader, qui est fixé à 115200 bauds.
    Ce commentaire s’applique par contre parfaitement à cette commande « screen /dev/ttyACM0 115200″

    Merci pour le tuto.

  3. Merci pour le billet.

    J’ai reçu mon premier arduino il y a une petite semaine, et l’IDE est à présent en version 1. Par contre, c’est une s*l*perie à utiliser, surtout quand on est un bon afficionado de vim. Pour couronner le tout, j’ai toujours détester les appli java.

    C’est vrai qu’avec un bon Makefile, voire un script pour générer un makefile minimal, c’est bien plus pratique.

  4. bonjour,

    j’ai un problème, je travaille sous windows et dans l’inviter de commande j’ai une erreurs a la compilation :s

    voila ma commande:

    avr-g++ -c -g -Os -w -fno-exceptions -ffunction-sections -fdata-sections -mmcu=atmega328p -DF_CPU=16000000L -DARDUINO=22 -I C:\arduino-0022\arduino-0022\hardware\arduino\cores\arduino\ -o blink.o blink.cpp

    il me dit no such file or directory et no input file, en gros il ne trouve pas le fichier donc je pense qu’il y a un problème de syntaxe, puisque c’est dans ce dossier que ce trouve le blink.cpp, si quelqu’un connais la solution..

    Merci d’avance

    Alex.

  5. Bonjour a tous,

    Merci pour ce tuto, mais j’ai une question, quelles sont les 13 sources à compiler et à créer les .o dans le dossier core?

    Bonne journée,

    Jack

  6. moi j’ai rien compris
    je suis dédutants en éléctronique
    des programmation jamai fait et l’anglai je comprend rien

    avez vous plus simple comme explication

  7. Si je créé un.hex a partir d’un autre IDE que celui de arduino AVR studio 6 par exemple (je maitrise le C). Puis je me contenter d’utiliser seulement la fonction chargement de l’IDE arduino ? Je préfère en effet une programmation de plus bas niveau que le pseudo langage arduino ( C voire assembleur). Placer le .hex dans le répertoire as hoc que lit arduino est il suffisant ? Merci

  8. bonjour je début sur arduino et j’ai se code erreur qui me bloque pouvez-vous m aidée svp This report would have more information with
    « Show verbose output during compilation »
    enabled in File > Preferences.
    Arduino: 1.0.6 (Windows Vista), Board: « Arduino Uno »
    minie.cpp.o: In function `__static_initialization_and_destruction_0′:
    C:\Program Files\Arduino/minie.ino:219: undefined reference to `DateTime::DateTime(long)’
    C:\Program Files\Arduino/minie.ino:459: undefined reference to `DateTime::DateTime(long)’
    minie.cpp.o: In function `check_programFuture()':
    C:\Program Files\Arduino/mE_program.ino:58: undefined reference to `DateTime::get() const’
    C:\Program Files\Arduino/mE_program.ino:58: undefined reference to `DateTime::get() const’
    minie.cpp.o: In function `paint_status_program_time()':
    C:\Program Files\Arduino/mE_ui_content.ino:1350: undefined reference to `DateTime::get() const’
    C:\Program Files\Arduino/mE_ui_content.ino:1374: undefined reference to `DateTime::DateTime(long)’
    C:\Program Files\Arduino/mE_ui_content.ino:1377: undefined reference to `DateTime::DateTime(long)’
    C:\Program Files\Arduino/mE_ui_content.ino:1380: undefined reference to `DateTime::DateTime(long)’
    C:\Program Files\Arduino/mE_ui_content.ino:1383: undefined reference to `DateTime::DateTime(long)’
    C:\Program Files\Arduino/mE_ui_content.ino:1386: undefined reference to `DateTime::DateTime(long)’
    minie.cpp.o: In function `paint_status_time()':
    C:\Program Files\Arduino/mE_ui_content.ino:1240: undefined reference to `DateTime::get() const’
    C:\Program Files\Arduino/mE_ui_content.ino:1240: undefined reference to `DateTime::DateTime(long)’
    C:\Program Files\Arduino/mE_ui_content.ino:1243: undefined reference to `DateTime::get() const’
    C:\Program Files\Arduino/mE_ui_content.ino:1243: undefined reference to `DateTime::DateTime(long)’
    C:\Program Files\Arduino/mE_ui_content.ino:1246: undefined reference to `DateTime::get() const’
    C:\Program Files\Arduino/mE_ui_content.ino:1246: undefined reference to `DateTime::DateTime(long)’
    C:\Program Files\Arduino/mE_ui_content.ino:1249: undefined reference to `DateTime::get() const’
    C:\Program Files\Arduino/mE_ui_content.ino:1249: undefined reference to `DateTime::DateTime(long)’
    C:\Program Files\Arduino/mE_ui_content.ino:1252: undefined reference to `DateTime::get() const’
    C:\Program Files\Arduino/mE_ui_content.ino:1252: undefined reference to `DateTime::DateTime(long)’
    C:\Program Files\Arduino/mE_ui_content.ino:1255: undefined reference to `DateTime::get() const’
    C:\Program Files\Arduino/mE_ui_content.ino:1255: undefined reference to `DateTime::DateTime(long)’
    C:\Program Files\Arduino/mE_ui_content.ino:1261: undefined reference to `RTC_DS1307::adjust(DateTime const&)’
    minie.cpp.o: In function `add_newProgram()':
    C:\Program Files\Arduino/mE_program.ino:88: undefined reference to `RTC_DS1307::now()’
    minie.cpp.o: In function `check_programs()':
    C:\Program Files\Arduino/mE_program.ino:183: undefined reference to `DateTime::dayOfWeek() const’
    minie.cpp.o: In function `load_config()':
    C:\Program Files\Arduino/mE_eeprom.ino:341: undefined reference to `DateTime::DateTime(long)’
    minie.cpp.o: In function `write_config()':
    C:\Program Files\Arduino/mE_eeprom.ino:257: undefined reference to `DateTime::get() const’
    minie.cpp.o: In function `loop':
    C:\Program Files\Arduino/minie.ino:774: undefined reference to `RTC_DS1307::now()’

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *

Vous pouvez utiliser ces balises et attributs HTML : <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>