Programmer en C sur l’esieabot

pigpiod

Pour programmer sur l’esieabot, nous utilisons pigpiod. pigpio est une bibliothèque qui permet de contrôler les GPIOs. Contrairement à WiringPi, elle est toujours maintenue à ce jour. pigpiod est une manière d’utiliser pigpio avec un service central permettant de lancer plusieurs programmes à la fois, sans monopoliser les GPIOs.

Cette documentation est un condensé de la documentation officielle de pigpiod.

Compiler un programme avec pigpiod

gcc fichier.c -o executable -lpigpiod_if2

Pour compiler un programme qui utilise la bibliothèque pigpiod, vous devez ajouter l’option -lpigpiod_if2 à votre commande gcc.

#include <pigpiod_if2.h>

Il nous vous reste ensuite qu’à ajouter le header de la bibliothèque de votre code.

Principes de base

Lorsque vous exécutez un programme utilisant pigpiod, celui-ci communique avec le service pigpiod afin de transmettre ses commandes. Vous devez donc vous assurez avant de lancer un programme que le service est bien en cours d’exécution avec la commande systemctl status pigpiod. Plusieurs programmes peuvent être exécutés en même temps. Si ils envoient des commandes contradictoires, pigpiod ne prendra en compte que la dernière commande qu’il aura reçu.

Comme sur un Arduino, il existe une multitude de broches GPIOs qui peuvent être utilisées. Plus d’information dans la documentation du Raspberry Pi. Un certain nombre de GPIO sont déjà utilisés sur votre esieabot pour les fonctions de base. Référez vous au manuel d’assemblage de votre esieabot.

Comme sur un Arduino, les GPIOs peuvent utilisés comme entrée ou sortie, pour recevoir ou envoyé des signaux logiques. Sur un Raspberry Pi, les signaux logiques doivent être à 3.3V et non 5V. Dans tous les cas, il faut, au début du programme, initialiser la connexion avec le service pigpiod avec cette function :

int pi = pigpio_start(NULL, NULL);

if (pi < 0) {
    printf("Can't connect to pigpiod\n");
    exit(-1);
}

Par la suite, la variable pi représente l’entité de l’esieabot. Pour interrompre la connexion avec le service pigpiod, il faut utiliser la fonction suivante en fin de programme :

pigpio_stop(pi);

Note

Dans les exemples qui vont suivre, il faut inclure unistd.h pour utiliser la fonction sleep().

« Hello World! » des GPIOs : allumer une LED

Tout d’abord, il faut brancher la LED à un GPIO inutilisé, par exemple sur le GPIO 16. Attention à ne pas oublier de mettre une résistance en série pour limiter le courant.

../_images/LED.png

Ensuite, il faut définir le GPIO 16 comme étant une sortie avec la fonction suivante :

set_mode(pi, 16, PI_OUTPUT); // Met le GPIO 16 en mode sortie

Enfin, il est possible de l’allumer et de l’éteindre avec cette boucle simple :

while(1) {
    gpio_write(pi, 16, PI_HIGH); // Envoi un signal "HAUT" sur le GPIO 16 pour l'allumer
    sleep(1);
    gpio_write(pi, 16, PI_LOW); // Envoi un signal "BAS" sur le GPIO16 pour l'éteindre
    sleep(1);
}

Si tout est bien branché, vous devriez avoir une LED qui clignote toutes les secondes !

Utiliser un bouton poussoir

Tout d’abord il faut brancher le bouton poussoir à un GPIO inutilisé, par exemple le GPIO 16.

../_images/Button.png

Avertissement

Attention au sens du bouton poussoir. Vérifiez avec un multimètre dans le doute.

Note

Dans cette situation, quand le bouton poussoir sera pressé un signal de 3.3V sera reçu par le GPIO 16. Sinon, rien ne sera envoyé et le GPIO 16 sera dans un état indéfini. Pour palier à cela, nous allons utiliser le mode « PULL DOWN ». Cela signifie que nous allons dire au Raspberry Pi de « brancher » le GPIO 16 à une résistance interne de rappel reliée à la masse, pour mettre par défaut le GPIO 16 à un 0 logique et non pas dans un état électrique incertain. Ainsi, lorsque le bouton poussoir ne sera pas pressé, on obtiendra un 0 logique lorsque l’on essaiera de lire la valeur du GPIO 16, puisque le GPIO 16 sera reliée à la masse via cette resistance de rappel.

Pour initialiser le bouton poussoir, on procédera donc ainsi :

set_mode(pi, 16, PI_INPUT); // Met le GPIO 16 en mode entrée
set_pull_up_down(pi, 16, PI_PUD_DOWN); // Active la résistance de rappel sur le GPIO 16

Nous avons ensuite deux méthodes possibles pour lire l’état du bouton poussoir. Tout d’abord la méthode dite du « polling », qui va consister à lire en boucle l’état du GPIO pour savoir si il y a eu un changement ou alors la méthode dite de l’interruption, qui va consister à surveiller l’état du GPIO en arrière plan et exécuter une fonction dès que celui-ci change.

Avertissement

Quelque soit la méthode utilisée, les bouton poussoirs peuvent subir un effet « rebond », c’est à dire que le signal peut ne pas être stable quelques instants après avoir appuyé physiquement dessus. Pour contrer cela, on peut rajouter un délai supplémentaire pour ignorer de potentiels changements rapides.

Polling

while (1) {
    int state = gpio_read(pi, 16); // Lecture de l'état du bouton poussoir
    if (state == PI_HIGH) { // Si le GPIO a reçu un "HAUT"
        printf("Le bouton poussoir sur le GPIO 16 est enclenché\n");
    } else if (state == PI_LOW) { // Si le GPIO a reçu un "BAS"
        printf("Le bouton poussoir sur le GPIO 16 est relaché\n");
    } else { // Ne devrait pas exister
        printf("Le GPIO 16 est dans un état inconnu\n");
    }
    sleep(1);
}

Interruption

void ma_fonction() {
    printf("J'ai été appelé car l'état du bouton poussoir a changé\n");
}
Dans la fonction main()
callback(pi, 16, RISING_EDGE, ma_fonction); // On créé le callback, qui va appelé la fonction
                                             // "ma_fonction" (sans paranthèse) lorsque l'état
                                             // du GPIO 16 sera sur une courbe montante
                                             // (par exemple quand le bouton poussoir vient d'être appuyé)

while(1) {
    printf("Il ne se passe strictement rien dans cette boucle.\n");
    printf("Mais comme j'ai créé un callback, si le bouton poussoir est appuyé, ma_fonction() sera appelée.\n\n");
    sleep(1);
}

Utiliser un pont en H

Les commandes pour utiliser un pont en H sont les mêmes que pour contrôler une LED puisque ce dernier n’a besoin que de recevoir des signaux logiques pour allumer et éteindre un moteur. Référez vous à la documentation du pont en H et au manuel d’assemblage pour connaître les signaux à envoyer.

Utiliser un servomoteur

Pour utiliser un servomoteur, il faut envoyer des signaux de durée très précise afin de communiquer une consigne d’angle. Plus d’information sur la documentation du servomoteur. Avec la bibliothèque pigpiod, on peut directement transmettre une consigne d’angle à un servomoteur, sans devoir s’occuper des signaux précis. Les consignes varient de 500 à 2500. 0 permet de désarmer le servomoteur. N’importe quel GPIO peut être utilisé comme source des signaux. Pour une meilleure précision (afin d’éviter des effets de « jitter ») il est possible d’utiliser les ports de PWM matériel du Raspberry Pi.

../_images/Servo.png
set_mode(pi, 16, PI_OUTPUT); // Met le GPIO 16 en mode sortie
set_servo_pulsewidth(pi, 16, 500); // Positionne le servo moteur au minimum
sleep(1);
set_servo_pulsewidth(pi, 16, 1500); // Positionne le servo moteur au milieu
sleep(1);
set_servo_pulsewidth(pi, 16, 2500); // Positionne le servo moteur au maximum
sleep(1);
set_servo_pulsewidth(pi, 16, 0); // Désarme le servo moteur

Emettre un signal PWM

Un signal PWM (Pulse Width Modulation) permet de contrôler un composant électronique comme si il était contrôlé par un signal analogique qui varie en tension. Pour cela, on va emettre très rapidemenet des signaux HAUT et BAS à une largeur de bande qui varie en fonction de la tension moyenne souhaitée. Avec un Raspberry Pi, tous les GPIOs peuvent être utilisés pour emettre ce genre de signaux. Cela permet concrètement de pouvoir faire varier la luminosité d’une LED ou la vitesse d’un moteur à courant continu.

../_images/PWM.gif

Illustration PyroElectro, http://www.pyroelectro.com/tutorials/fading_led_pwm/theory.html

Avec pigpiod, on utilise la fonction set_PWM_dutycycle() pour émettre un signal PWM. La largeur de bande demandée doit être comprise entre 0 et 255. 0 correspond à éteindre, 255 à allumer pleinement.

set_mode(pi, 16, PI_OUTPUT); // Met le GPIO 16 en mode sortie
set_PWM_dutycycle(pi, 16, 0); // Produit une tension moyenne de 0V (comme si on émettait un signal BAS)
sleep(1);
set_PWM_dutycycle(pi, 16, 128); // Produit une tension moyenne de 1.65V (la moitié de 3.3V)
sleep(1);
set_PWM_dutycycle(pi, 16, 255); // Produit une tension moyenne de 3.3V (comme si on émettait un signal HAUT)